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

Bug#1112449: bookworm-pu: package perl/5.36.0-7+deb12u3



Package: release.debian.org
Severity: normal
Tags: bookworm
User: release.debian.org@packages.debian.org
Usertags: pu
X-Debbugs-Cc: perl@packages.debian.org, perl@packages.debian.org, carnil@debian.org
Control: affects -1 + src:perl

Hi stable release managers,

I'd like to fix two security issues for bookworm that were deemed no-DSA
by the security team / Salvatore (cc'd).

Although the debdiff is rather cluttered due to build system complexity,
I'm still assuming this is not controversial. So I've just uploaded this:

 perl (5.36.0-7+deb12u3) bookworm; urgency=medium
 .
   * [SECURITY] CVE-2023-31484: CPAN.pm now verifies TLS certificates.
                                (Closes: #1035109)
   * [SECURITY] CVE-2025-40909: Clone dirhandles without fchdir
                                (Closes: #1098226)

[ Impact ]
Two non-critical security issues in bookworm.

[ Tests ]
I've tested manually that the update fixes the above issues. There's
an extensive build time test suite that still passes, and so does the
small set of autopkgtest checks.

I have not done major rebuild or autopkgtest testing of perl reverse
dependencies. I did that for CVE-2025-40909 in trixie/sid (see #1108676)
and found no regressions.

This time I also tested that cross building still works, at least
for amd64 -> armhf. (Missed this in my first CVE-2025-40909 update
for trixie.)

[ Risks ]
The fixes are targeted.

CVE-2023-31484 fix is trivial and should only affect users who install
Perl modules directly from CPAN rather than packaged versions in Debian.

The CVE-2025-40909 clutter is limited to build time; the runtime change
is small.

[ Checklist ]
  [X] *all* changes are documented in the d/changelog
  [X] I reviewed all changes and I approve them
  [X] attach debdiff against the package in (old)stable
  [X] the issue is verified as fixed in unstable

[ Changes ]

The CVE-2025-40909 fix took a while for upstream to get right, so there's
three cherry picked commits as separate patches. Furthermore, the changes
to the top level Configure script needed two other patches so we can
keep the Configure regeneration machinery working. (See #762638 for the
background on why we have this machinery.)

I also had to make trivial updates to the cross build support files in
debian/cross for every supported architecture. See #1109972 for some
details on why this was necessary. These files are never used for
native builds, so regressions seem very improbable.

Unfortunately this all means that the debdiff is rather cluttered. Sorry
about that.  For your convenience, I'm also attaching a squashed version
of the upstream changes (output of ` git diff debian/5.36.0-7+deb12u2
debian/5.36.0-7+deb12u3 ':!debian/' `) as `perl_5.36.0-7+deb12u3.gitdiff`.

[ Other info ]

The CVE-2025-40909 upstream changes actually remove a few existing
test cases, because they were testing behaviour that cannot
be retained while fixing the bug. Upstream decided that having
independent directory handles after thread creation didn't make sense
anyway, particularly as file handles never behaved like this. See
https://github.com/Perl/perl5/pull/23019 for the discussion.
diff -Nru perl-5.36.0/debian/changelog perl-5.36.0/debian/changelog
--- perl-5.36.0/debian/changelog	2025-04-12 18:16:31.000000000 +0300
+++ perl-5.36.0/debian/changelog	2025-08-29 15:09:36.000000000 +0300
@@ -1,3 +1,12 @@
+perl (5.36.0-7+deb12u3) bookworm; urgency=medium
+
+  * [SECURITY] CVE-2023-31484: CPAN.pm now verifies TLS certificates.
+                               (Closes: #1035109)
+  * [SECURITY] CVE-2025-40909: Clone dirhandles without fchdir
+                               (Closes: #1098226)
+
+ -- Niko Tyni <ntyni@debian.org>  Fri, 29 Aug 2025 15:09:36 +0300
+
 perl (5.36.0-7+deb12u2) bookworm-security; urgency=medium
 
   * [SECURITY] CVE-2024-56406: Fix heap-buffer-overflow with tr//
diff -Nru perl-5.36.0/debian/cross/alpha/config.sh.static perl-5.36.0/debian/cross/alpha/config.sh.static
--- perl-5.36.0/debian/cross/alpha/config.sh.static	2025-04-12 18:08:53.000000000 +0300
+++ perl-5.36.0/debian/cross/alpha/config.sh.static	2025-08-29 15:04:15.000000000 +0300
@@ -256,6 +256,7 @@
 d_fd_set='define'
 d_fdclose='undef'
 d_fdim='define'
+d_fdopendir='define'
 d_fds_bits='define'
 d_fegetround='define'
 d_ffs='define'
diff -Nru perl-5.36.0/debian/cross/amd64/config.sh.static perl-5.36.0/debian/cross/amd64/config.sh.static
--- perl-5.36.0/debian/cross/amd64/config.sh.static	2025-04-12 18:08:53.000000000 +0300
+++ perl-5.36.0/debian/cross/amd64/config.sh.static	2025-08-29 15:04:15.000000000 +0300
@@ -256,6 +256,7 @@
 d_fd_set='define'
 d_fdclose='undef'
 d_fdim='define'
+d_fdopendir='define'
 d_fds_bits='define'
 d_fegetround='define'
 d_ffs='define'
diff -Nru perl-5.36.0/debian/cross/arm64/config.sh.static perl-5.36.0/debian/cross/arm64/config.sh.static
--- perl-5.36.0/debian/cross/arm64/config.sh.static	2025-04-12 18:08:53.000000000 +0300
+++ perl-5.36.0/debian/cross/arm64/config.sh.static	2025-08-29 15:04:15.000000000 +0300
@@ -256,6 +256,7 @@
 d_fd_set='define'
 d_fdclose='undef'
 d_fdim='define'
+d_fdopendir='define'
 d_fds_bits='define'
 d_fegetround='define'
 d_ffs='define'
diff -Nru perl-5.36.0/debian/cross/armel/config.sh.static perl-5.36.0/debian/cross/armel/config.sh.static
--- perl-5.36.0/debian/cross/armel/config.sh.static	2025-04-12 18:08:53.000000000 +0300
+++ perl-5.36.0/debian/cross/armel/config.sh.static	2025-08-29 15:04:15.000000000 +0300
@@ -256,6 +256,7 @@
 d_fd_set='define'
 d_fdclose='undef'
 d_fdim='define'
+d_fdopendir='define'
 d_fds_bits='define'
 d_fegetround='define'
 d_ffs='define'
diff -Nru perl-5.36.0/debian/cross/armhf/config.sh.static perl-5.36.0/debian/cross/armhf/config.sh.static
--- perl-5.36.0/debian/cross/armhf/config.sh.static	2025-04-12 18:08:53.000000000 +0300
+++ perl-5.36.0/debian/cross/armhf/config.sh.static	2025-08-29 15:04:15.000000000 +0300
@@ -256,6 +256,7 @@
 d_fd_set='define'
 d_fdclose='undef'
 d_fdim='define'
+d_fdopendir='define'
 d_fds_bits='define'
 d_fegetround='define'
 d_ffs='define'
diff -Nru perl-5.36.0/debian/cross/hppa/config.sh.static perl-5.36.0/debian/cross/hppa/config.sh.static
--- perl-5.36.0/debian/cross/hppa/config.sh.static	2025-04-12 18:08:53.000000000 +0300
+++ perl-5.36.0/debian/cross/hppa/config.sh.static	2025-08-29 15:04:15.000000000 +0300
@@ -256,6 +256,7 @@
 d_fd_set='define'
 d_fdclose='undef'
 d_fdim='define'
+d_fdopendir='define'
 d_fds_bits='define'
 d_fegetround='define'
 d_ffs='define'
diff -Nru perl-5.36.0/debian/cross/hurd-i386/config.sh.static perl-5.36.0/debian/cross/hurd-i386/config.sh.static
--- perl-5.36.0/debian/cross/hurd-i386/config.sh.static	2025-04-12 18:08:53.000000000 +0300
+++ perl-5.36.0/debian/cross/hurd-i386/config.sh.static	2025-08-29 15:04:15.000000000 +0300
@@ -256,6 +256,7 @@
 d_fd_set='define'
 d_fdclose='undef'
 d_fdim='define'
+d_fdopendir='define'
 d_fds_bits='define'
 d_fegetround='define'
 d_ffs='define'
diff -Nru perl-5.36.0/debian/cross/i386/config.sh.static perl-5.36.0/debian/cross/i386/config.sh.static
--- perl-5.36.0/debian/cross/i386/config.sh.static	2025-04-12 18:08:53.000000000 +0300
+++ perl-5.36.0/debian/cross/i386/config.sh.static	2025-08-29 15:04:15.000000000 +0300
@@ -256,6 +256,7 @@
 d_fd_set='define'
 d_fdclose='undef'
 d_fdim='define'
+d_fdopendir='define'
 d_fds_bits='define'
 d_fegetround='define'
 d_ffs='define'
diff -Nru perl-5.36.0/debian/cross/ia64/config.sh.static perl-5.36.0/debian/cross/ia64/config.sh.static
--- perl-5.36.0/debian/cross/ia64/config.sh.static	2025-04-12 18:08:53.000000000 +0300
+++ perl-5.36.0/debian/cross/ia64/config.sh.static	2025-08-29 15:04:15.000000000 +0300
@@ -256,6 +256,7 @@
 d_fd_set='define'
 d_fdclose='undef'
 d_fdim='define'
+d_fdopendir='define'
 d_fds_bits='define'
 d_fegetround='define'
 d_ffs='define'
diff -Nru perl-5.36.0/debian/cross/kfreebsd-amd64/config.sh.static perl-5.36.0/debian/cross/kfreebsd-amd64/config.sh.static
--- perl-5.36.0/debian/cross/kfreebsd-amd64/config.sh.static	2024-10-01 23:10:23.000000000 +0300
+++ perl-5.36.0/debian/cross/kfreebsd-amd64/config.sh.static	2025-08-24 13:46:33.000000000 +0300
@@ -256,6 +256,7 @@
 d_fd_set='define'
 d_fdclose='undef'
 d_fdim='define'
+d_fdopendir='define'
 d_fds_bits='define'
 d_fegetround='define'
 d_fgetpos='define'
diff -Nru perl-5.36.0/debian/cross/kfreebsd-i386/config.sh.static perl-5.36.0/debian/cross/kfreebsd-i386/config.sh.static
--- perl-5.36.0/debian/cross/kfreebsd-i386/config.sh.static	2024-10-01 23:10:23.000000000 +0300
+++ perl-5.36.0/debian/cross/kfreebsd-i386/config.sh.static	2025-08-24 13:46:33.000000000 +0300
@@ -256,6 +256,7 @@
 d_fd_set='define'
 d_fdclose='undef'
 d_fdim='define'
+d_fdopendir='define'
 d_fds_bits='define'
 d_fegetround='define'
 d_fgetpos='define'
diff -Nru perl-5.36.0/debian/cross/m68k/config.sh.static perl-5.36.0/debian/cross/m68k/config.sh.static
--- perl-5.36.0/debian/cross/m68k/config.sh.static	2025-04-12 18:08:53.000000000 +0300
+++ perl-5.36.0/debian/cross/m68k/config.sh.static	2025-08-29 15:04:15.000000000 +0300
@@ -256,6 +256,7 @@
 d_fd_set='define'
 d_fdclose='undef'
 d_fdim='define'
+d_fdopendir='define'
 d_fds_bits='define'
 d_fegetround='define'
 d_ffs='define'
diff -Nru perl-5.36.0/debian/cross/mips/config.sh.static perl-5.36.0/debian/cross/mips/config.sh.static
--- perl-5.36.0/debian/cross/mips/config.sh.static	2024-10-01 23:10:23.000000000 +0300
+++ perl-5.36.0/debian/cross/mips/config.sh.static	2025-08-24 13:46:33.000000000 +0300
@@ -255,6 +255,7 @@
 d_fd_set='define'
 d_fdclose='undef'
 d_fdim='define'
+d_fdopendir='define'
 d_fds_bits='define'
 d_fegetround='define'
 d_fgetpos='define'
diff -Nru perl-5.36.0/debian/cross/mips64el/config.sh.static perl-5.36.0/debian/cross/mips64el/config.sh.static
--- perl-5.36.0/debian/cross/mips64el/config.sh.static	2025-04-12 18:08:53.000000000 +0300
+++ perl-5.36.0/debian/cross/mips64el/config.sh.static	2025-08-29 15:04:15.000000000 +0300
@@ -256,6 +256,7 @@
 d_fd_set='define'
 d_fdclose='undef'
 d_fdim='define'
+d_fdopendir='define'
 d_fds_bits='define'
 d_fegetround='define'
 d_ffs='define'
diff -Nru perl-5.36.0/debian/cross/mipsel/config.sh.static perl-5.36.0/debian/cross/mipsel/config.sh.static
--- perl-5.36.0/debian/cross/mipsel/config.sh.static	2024-10-01 23:10:23.000000000 +0300
+++ perl-5.36.0/debian/cross/mipsel/config.sh.static	2025-08-24 13:46:33.000000000 +0300
@@ -256,6 +256,7 @@
 d_fd_set='define'
 d_fdclose='undef'
 d_fdim='define'
+d_fdopendir='define'
 d_fds_bits='define'
 d_fegetround='define'
 d_ffs='define'
diff -Nru perl-5.36.0/debian/cross/powerpc/config.sh.static perl-5.36.0/debian/cross/powerpc/config.sh.static
--- perl-5.36.0/debian/cross/powerpc/config.sh.static	2025-04-12 18:08:53.000000000 +0300
+++ perl-5.36.0/debian/cross/powerpc/config.sh.static	2025-08-29 15:04:15.000000000 +0300
@@ -256,6 +256,7 @@
 d_fd_set='define'
 d_fdclose='undef'
 d_fdim='define'
+d_fdopendir='define'
 d_fds_bits='define'
 d_fegetround='define'
 d_ffs='define'
diff -Nru perl-5.36.0/debian/cross/powerpcspe/config.sh.static perl-5.36.0/debian/cross/powerpcspe/config.sh.static
--- perl-5.36.0/debian/cross/powerpcspe/config.sh.static	2024-10-01 23:10:23.000000000 +0300
+++ perl-5.36.0/debian/cross/powerpcspe/config.sh.static	2025-08-24 13:46:33.000000000 +0300
@@ -255,6 +255,7 @@
 d_fd_set='define'
 d_fdclose='undef'
 d_fdim='define'
+d_fdopendir='define'
 d_fds_bits='define'
 d_fegetround='define'
 d_fgetpos='define'
diff -Nru perl-5.36.0/debian/cross/ppc64/config.sh.static perl-5.36.0/debian/cross/ppc64/config.sh.static
--- perl-5.36.0/debian/cross/ppc64/config.sh.static	2025-04-12 18:08:53.000000000 +0300
+++ perl-5.36.0/debian/cross/ppc64/config.sh.static	2025-08-29 15:04:15.000000000 +0300
@@ -256,6 +256,7 @@
 d_fd_set='define'
 d_fdclose='undef'
 d_fdim='define'
+d_fdopendir='define'
 d_fds_bits='define'
 d_fegetround='define'
 d_ffs='define'
diff -Nru perl-5.36.0/debian/cross/ppc64el/config.sh.static perl-5.36.0/debian/cross/ppc64el/config.sh.static
--- perl-5.36.0/debian/cross/ppc64el/config.sh.static	2025-04-12 18:08:53.000000000 +0300
+++ perl-5.36.0/debian/cross/ppc64el/config.sh.static	2025-08-29 15:04:15.000000000 +0300
@@ -256,6 +256,7 @@
 d_fd_set='define'
 d_fdclose='undef'
 d_fdim='define'
+d_fdopendir='define'
 d_fds_bits='define'
 d_fegetround='define'
 d_ffs='define'
diff -Nru perl-5.36.0/debian/cross/riscv64/config.sh.static perl-5.36.0/debian/cross/riscv64/config.sh.static
--- perl-5.36.0/debian/cross/riscv64/config.sh.static	2025-04-12 18:08:53.000000000 +0300
+++ perl-5.36.0/debian/cross/riscv64/config.sh.static	2025-08-29 15:04:15.000000000 +0300
@@ -256,6 +256,7 @@
 d_fd_set='define'
 d_fdclose='undef'
 d_fdim='define'
+d_fdopendir='define'
 d_fds_bits='define'
 d_fegetround='define'
 d_ffs='define'
diff -Nru perl-5.36.0/debian/cross/s390x/config.sh.static perl-5.36.0/debian/cross/s390x/config.sh.static
--- perl-5.36.0/debian/cross/s390x/config.sh.static	2025-04-12 18:08:53.000000000 +0300
+++ perl-5.36.0/debian/cross/s390x/config.sh.static	2025-08-29 15:04:15.000000000 +0300
@@ -256,6 +256,7 @@
 d_fd_set='define'
 d_fdclose='undef'
 d_fdim='define'
+d_fdopendir='define'
 d_fds_bits='define'
 d_fegetround='define'
 d_ffs='define'
diff -Nru perl-5.36.0/debian/cross/sh4/config.sh.static perl-5.36.0/debian/cross/sh4/config.sh.static
--- perl-5.36.0/debian/cross/sh4/config.sh.static	2025-04-12 18:08:53.000000000 +0300
+++ perl-5.36.0/debian/cross/sh4/config.sh.static	2025-08-29 15:04:15.000000000 +0300
@@ -256,6 +256,7 @@
 d_fd_set='define'
 d_fdclose='undef'
 d_fdim='define'
+d_fdopendir='define'
 d_fds_bits='define'
 d_fegetround='define'
 d_ffs='define'
diff -Nru perl-5.36.0/debian/cross/sparc64/config.sh.static perl-5.36.0/debian/cross/sparc64/config.sh.static
--- perl-5.36.0/debian/cross/sparc64/config.sh.static	2025-04-12 18:08:53.000000000 +0300
+++ perl-5.36.0/debian/cross/sparc64/config.sh.static	2025-08-29 15:04:15.000000000 +0300
@@ -256,6 +256,7 @@
 d_fd_set='define'
 d_fdclose='undef'
 d_fdim='define'
+d_fdopendir='define'
 d_fds_bits='define'
 d_fegetround='define'
 d_ffs='define'
diff -Nru perl-5.36.0/debian/cross/x32/config.sh.static perl-5.36.0/debian/cross/x32/config.sh.static
--- perl-5.36.0/debian/cross/x32/config.sh.static	2025-04-12 18:08:53.000000000 +0300
+++ perl-5.36.0/debian/cross/x32/config.sh.static	2025-08-29 15:04:15.000000000 +0300
@@ -256,6 +256,7 @@
 d_fd_set='define'
 d_fdclose='undef'
 d_fdim='define'
+d_fdopendir='define'
 d_fds_bits='define'
 d_fegetround='define'
 d_ffs='define'
diff -Nru perl-5.36.0/debian/patches/fixes/CVE-2023-31484.diff perl-5.36.0/debian/patches/fixes/CVE-2023-31484.diff
--- perl-5.36.0/debian/patches/fixes/CVE-2023-31484.diff	1970-01-01 02:00:00.000000000 +0200
+++ perl-5.36.0/debian/patches/fixes/CVE-2023-31484.diff	2025-08-29 15:04:15.000000000 +0300
@@ -0,0 +1,25 @@
+From: Stig Palmquist <git@stig.io>
+Date: Tue, 28 Feb 2023 11:54:06 +0100
+Subject: Add verify_SSL=>1 to HTTP::Tiny to verify https server identity
+
+(Trivial backport for Debian Perl 5.36 by Niko Tyni <ntyni@debian.org>)
+
+Origin: backport, https://github.com/andk/cpanpm/commit/9c98370287f4e709924aee7c58ef21c85289a7f0
+Bug: https://github.com/andk/cpanpm/pull/175
+Bug-Debian: https://bugs.debian.org/1035109
+---
+ cpan/CPAN/lib/CPAN/HTTP/Client.pm | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/cpan/CPAN/lib/CPAN/HTTP/Client.pm b/cpan/CPAN/lib/CPAN/HTTP/Client.pm
+index 4fc792c..a616fee 100644
+--- a/cpan/CPAN/lib/CPAN/HTTP/Client.pm
++++ b/cpan/CPAN/lib/CPAN/HTTP/Client.pm
+@@ -32,6 +32,7 @@ sub mirror {
+ 
+     my $want_proxy = $self->_want_proxy($uri);
+     my $http = HTTP::Tiny->new(
++        verify_SSL => 1,
+         $want_proxy ? (proxy => $self->{proxy}) : ()
+     );
+ 
diff -Nru perl-5.36.0/debian/patches/fixes/CVE-2025-40909-1.diff perl-5.36.0/debian/patches/fixes/CVE-2025-40909-1.diff
--- perl-5.36.0/debian/patches/fixes/CVE-2025-40909-1.diff	1970-01-01 02:00:00.000000000 +0200
+++ perl-5.36.0/debian/patches/fixes/CVE-2025-40909-1.diff	2025-08-29 15:04:15.000000000 +0300
@@ -0,0 +1,413 @@
+From: Leon Timmermans <fawaka@gmail.com>
+Date: Fri, 23 May 2025 15:40:41 +0200
+Subject: CVE-2025-40909: Clone dirhandles without fchdir
+
+This uses fdopendir and dup to dirhandles. This means it won't change
+working directory during thread cloning, which prevents race conditions
+that can happen if a third thread is active at the same time.
+
+(cherry picked from commit 918bfff86ca8d6d4e4ec5b30994451e0bd74aba9)
+
+Origin: backport, https://github.com/Perl/perl5/commit/84be063eb88c5b1dd26cb4c418b94d39e60b7049
+Bug: https://github.com/Perl/perl5/issues/23010
+Bug-Debian: https://bugs.debian.org/1098226
+---
+ Configure                      |   6 +++
+ Cross/config.sh-arm-linux      |   1 +
+ Cross/config.sh-arm-linux-n770 |   1 +
+ Porting/Glossary               |   5 ++
+ Porting/config.sh              |   1 +
+ config_h.SH                    |   6 +++
+ configure.com                  |   1 +
+ plan9/config_sh.sample         |   1 +
+ sv.c                           |  91 ++----------------------------------
+ t/op/threads-dirh.t            | 104 +----------------------------------------
+ win32/config.gc                |   1 +
+ win32/config.vc                |   1 +
+ 12 files changed, 28 insertions(+), 191 deletions(-)
+
+diff --git a/Configure b/Configure
+index a7a64f7..9f1ad74 100755
+--- a/Configure
++++ b/Configure
+@@ -477,6 +477,7 @@ d_fd_set=''
+ d_fds_bits=''
+ d_fdclose=''
+ d_fdim=''
++d_fdopendir=''
+ d_fegetround=''
+ d_ffs=''
+ d_ffsl=''
+@@ -13335,6 +13336,10 @@ esac
+ set i_fcntl
+ eval $setvar
+ 
++: see if fdopendir exists
++set fdopendir d_fdopendir
++eval $inlibc
++
+ : see if fork exists
+ set fork d_fork
+ eval $inlibc
+@@ -24680,6 +24685,7 @@ d_flockproto='$d_flockproto'
+ d_fma='$d_fma'
+ d_fmax='$d_fmax'
+ d_fmin='$d_fmin'
++d_fdopendir='$d_fdopendir'
+ d_fork='$d_fork'
+ d_fp_class='$d_fp_class'
+ d_fp_classify='$d_fp_classify'
+diff --git a/Cross/config.sh-arm-linux b/Cross/config.sh-arm-linux
+index f230370..5297874 100644
+--- a/Cross/config.sh-arm-linux
++++ b/Cross/config.sh-arm-linux
+@@ -211,6 +211,7 @@ d_fd_macros='define'
+ d_fd_set='define'
+ d_fdclose='undef'
+ d_fdim='undef'
++d_fdopendir=undef
+ d_fds_bits='undef'
+ d_fegetround='define'
+ d_ffs='undef'
+diff --git a/Cross/config.sh-arm-linux-n770 b/Cross/config.sh-arm-linux-n770
+index b1e697f..ab5cfe9 100644
+--- a/Cross/config.sh-arm-linux-n770
++++ b/Cross/config.sh-arm-linux-n770
+@@ -210,6 +210,7 @@ d_fd_macros='define'
+ d_fd_set='define'
+ d_fdclose='undef'
+ d_fdim='undef'
++d_fdopendir=undef
+ d_fds_bits='undef'
+ d_fegetround='define'
+ d_ffs='undef'
+diff --git a/Porting/Glossary b/Porting/Glossary
+index 2dcb565..4d1b320 100644
+--- a/Porting/Glossary
++++ b/Porting/Glossary
+@@ -943,6 +943,11 @@ d_fmin (d_fmin.U):
+ 	This variable conditionally defines the HAS_FMIN symbol, which
+ 	indicates to the C program that the fmin() routine is available.
+ 
++d_fdopendir (d_fdopendir.U):
++	This variable conditionally defines the HAS_FORK symbol, which
++	indicates that the fdopen routine is available to open a
++	directory descriptor.
++
+ d_fork (d_fork.U):
+ 	This variable conditionally defines the HAS_FORK symbol, which
+ 	indicates to the C program that the fork() routine is available.
+diff --git a/Porting/config.sh b/Porting/config.sh
+index 91086e6..9bc04c6 100644
+--- a/Porting/config.sh
++++ b/Porting/config.sh
+@@ -227,6 +227,7 @@ d_fd_macros='define'
+ d_fd_set='define'
+ d_fdclose='undef'
+ d_fdim='define'
++d_fdopendir='define'
+ d_fds_bits='define'
+ d_fegetround='define'
+ d_ffs='undef'
+diff --git a/config_h.SH b/config_h.SH
+index b817483..5804966 100755
+--- a/config_h.SH
++++ b/config_h.SH
+@@ -142,6 +142,12 @@ sed <<!GROK!THIS! >$CONFIG_H -e 's!^#undef\(.*/\)\*!/\*#define\1 \*!' -e 's!^#un
+  */
+ #$d_fcntl HAS_FCNTL		/**/
+ 
++/* HAS_FDOPENDIR:
++ * This symbol, if defined, indicates that the fdopen routine is
++ * available to open a directory descriptor.
++ */
++#$d_fdopendir HAS_FDOPENDIR		/**/
++
+ /* HAS_FGETPOS:
+  *	This symbol, if defined, indicates that the fgetpos routine is
+  *	available to get the file position indicator, similar to ftell().
+diff --git a/configure.com b/configure.com
+index 1ea4197..d22d6ce 100644
+--- a/configure.com
++++ b/configure.com
+@@ -6213,6 +6213,7 @@ $ WC "d_fd_set='" + d_fd_set + "'"
+ $ WC "d_fd_macros='define'"
+ $ WC "d_fdclose='undef'"
+ $ WC "d_fdim='" + d_fdim + "'"
++$ WC "d_fdopendir='undef'"
+ $ WC "d_fds_bits='define'"
+ $ WC "d_fegetround='undef'"
+ $ WC "d_ffs='undef'"
+diff --git a/plan9/config_sh.sample b/plan9/config_sh.sample
+index 02b4657..4731443 100644
+--- a/plan9/config_sh.sample
++++ b/plan9/config_sh.sample
+@@ -211,6 +211,7 @@ d_fd_macros='undef'
+ d_fd_set='undef'
+ d_fdclose='undef'
+ d_fdim='undef'
++d_fdopendir=undef
+ d_fds_bits='undef'
+ d_fegetround='undef'
+ d_ffs='undef'
+diff --git a/sv.c b/sv.c
+index 16bba94..26807ce 100644
+--- a/sv.c
++++ b/sv.c
+@@ -13700,15 +13700,6 @@ Perl_dirp_dup(pTHX_ DIR *const dp, CLONE_PARAMS *const param)
+ {
+     DIR *ret;
+ 
+-#if defined(HAS_FCHDIR) && defined(HAS_TELLDIR) && defined(HAS_SEEKDIR)
+-    DIR *pwd;
+-    const Direntry_t *dirent;
+-    char smallbuf[256]; /* XXX MAXPATHLEN, surely? */
+-    char *name = NULL;
+-    STRLEN len = 0;
+-    long pos;
+-#endif
+-
+     PERL_UNUSED_CONTEXT;
+     PERL_ARGS_ASSERT_DIRP_DUP;
+ 
+@@ -13720,89 +13711,13 @@ Perl_dirp_dup(pTHX_ DIR *const dp, CLONE_PARAMS *const param)
+     if (ret)
+         return ret;
+ 
+-#if defined(HAS_FCHDIR) && defined(HAS_TELLDIR) && defined(HAS_SEEKDIR)
++#ifdef HAS_FDOPENDIR
+ 
+     PERL_UNUSED_ARG(param);
+ 
+-    /* create anew */
+-
+-    /* open the current directory (so we can switch back) */
+-    if (!(pwd = PerlDir_open("."))) return (DIR *)NULL;
+-
+-    /* chdir to our dir handle and open the present working directory */
+-    if (fchdir(my_dirfd(dp)) < 0 || !(ret = PerlDir_open("."))) {
+-        PerlDir_close(pwd);
+-        return (DIR *)NULL;
+-    }
+-    /* Now we should have two dir handles pointing to the same dir. */
+-
+-    /* Be nice to the calling code and chdir back to where we were. */
+-    /* XXX If this fails, then what? */
+-    PERL_UNUSED_RESULT(fchdir(my_dirfd(pwd)));
++    ret = fdopendir(dup(my_dirfd(dp)));
+ 
+-    /* We have no need of the pwd handle any more. */
+-    PerlDir_close(pwd);
+-
+-#ifdef DIRNAMLEN
+-# define d_namlen(d) (d)->d_namlen
+-#else
+-# define d_namlen(d) strlen((d)->d_name)
+-#endif
+-    /* Iterate once through dp, to get the file name at the current posi-
+-       tion. Then step back. */
+-    pos = PerlDir_tell(dp);
+-    if ((dirent = PerlDir_read(dp))) {
+-        len = d_namlen(dirent);
+-        if (len > sizeof(dirent->d_name) && sizeof(dirent->d_name) > PTRSIZE) {
+-            /* If the len is somehow magically longer than the
+-             * maximum length of the directory entry, even though
+-             * we could fit it in a buffer, we could not copy it
+-             * from the dirent.  Bail out. */
+-            PerlDir_close(ret);
+-            return (DIR*)NULL;
+-        }
+-        if (len <= sizeof smallbuf) name = smallbuf;
+-        else Newx(name, len, char);
+-        Move(dirent->d_name, name, len, char);
+-    }
+-    PerlDir_seek(dp, pos);
+-
+-    /* Iterate through the new dir handle, till we find a file with the
+-       right name. */
+-    if (!dirent) /* just before the end */
+-        for(;;) {
+-            pos = PerlDir_tell(ret);
+-            if (PerlDir_read(ret)) continue; /* not there yet */
+-            PerlDir_seek(ret, pos); /* step back */
+-            break;
+-        }
+-    else {
+-        const long pos0 = PerlDir_tell(ret);
+-        for(;;) {
+-            pos = PerlDir_tell(ret);
+-            if ((dirent = PerlDir_read(ret))) {
+-                if (len == (STRLEN)d_namlen(dirent)
+-                    && memEQ(name, dirent->d_name, len)) {
+-                    /* found it */
+-                    PerlDir_seek(ret, pos); /* step back */
+-                    break;
+-                }
+-                /* else we are not there yet; keep iterating */
+-            }
+-            else { /* This is not meant to happen. The best we can do is
+-                      reset the iterator to the beginning. */
+-                PerlDir_seek(ret, pos0);
+-                break;
+-            }
+-        }
+-    }
+-#undef d_namlen
+-
+-    if (name && name != smallbuf)
+-        Safefree(name);
+-#endif
+-
+-#ifdef WIN32
++#elif defined(WIN32)
+     ret = win32_dirp_dup(dp, param);
+ #endif
+ 
+diff --git a/t/op/threads-dirh.t b/t/op/threads-dirh.t
+index bb4bcfc..14c399c 100644
+--- a/t/op/threads-dirh.t
++++ b/t/op/threads-dirh.t
+@@ -13,16 +13,12 @@ BEGIN {
+      skip_all_if_miniperl("no dynamic loading on miniperl, no threads");
+      skip_all("runs out of memory on some EBCDIC") if $ENV{PERL_SKIP_BIG_MEM_TESTS};
+ 
+-     plan(6);
++     plan(1);
+ }
+ 
+ use strict;
+ use warnings;
+ use threads;
+-use threads::shared;
+-use File::Path;
+-use File::Spec::Functions qw 'updir catdir';
+-use Cwd 'getcwd';
+ 
+ # Basic sanity check: make sure this does not crash
+ fresh_perl_is <<'# this is no comment', 'ok', {}, 'crash when duping dirh';
+@@ -31,101 +27,3 @@ fresh_perl_is <<'# this is no comment', 'ok', {}, 'crash when duping dirh';
+    async{}->join for 1..2;
+    print "ok";
+ # this is no comment
+-
+-my $dir;
+-SKIP: {
+- skip "telldir or seekdir not defined on this platform", 5
+-    if !$Config::Config{d_telldir} || !$Config::Config{d_seekdir};
+- my $skip = sub {
+-   chdir($dir);
+-   chdir updir;
+-   skip $_[0], 5
+- };
+-
+- if(!$Config::Config{d_fchdir} && $^O ne "MSWin32") {
+-  $::TODO = 'dir handle cloning currently requires fchdir on non-Windows platforms';
+- }
+-
+- my @w :shared; # warnings accumulator
+- local $SIG{__WARN__} = sub { push @w, $_[0] };
+-
+- $dir = catdir getcwd(), "thrext$$" . int rand() * 100000;
+-
+- rmtree($dir) if -d $dir;
+- mkdir($dir);
+-
+- # Create a dir structure like this:
+- #   $dir
+- #     |
+- #     `- toberead
+- #            |
+- #            +---- thrit
+- #            |
+- #            +---- rile
+- #            |
+- #            `---- zor
+-
+- chdir($dir);
+- mkdir 'toberead';
+- chdir 'toberead';
+- {open my $fh, ">thrit" or &$skip("Cannot create file thrit")}
+- {open my $fh, ">rile" or &$skip("Cannot create file rile")}
+- {open my $fh, ">zor" or &$skip("Cannot create file zor")}
+- chdir updir;
+-
+- # Then test that dir iterators are cloned correctly.
+-
+- opendir my $toberead, 'toberead';
+- my $start_pos = telldir $toberead;
+- my @first_2 = (scalar readdir $toberead, scalar readdir $toberead);
+- my @from_thread = @{; async { [readdir $toberead ] } ->join };
+- my @from_main = readdir $toberead;
+- is join('-', sort @from_thread), join('-', sort @from_main),
+-     'dir iterator is copied from one thread to another';
+- like
+-   join('-', "", sort(@first_2, @from_thread), ""),
+-   qr/(?<!-rile)-rile-thrit-zor-(?!zor-)/i,
+-  'cloned iterator iterates exactly once over everything not already seen';
+-
+- seekdir $toberead, $start_pos;
+- readdir $toberead for 1 .. @first_2+@from_thread;
+- {
+-  local $::TODO; # This always passes when dir handles are not cloned.
+-  is
+-    async { readdir $toberead // 'undef' } ->join, 'undef',
+-   'cloned dir iterator that points to the end of the directory'
+-  ;
+- }
+-
+- # Make sure the cloning code can handle file names longer than 255 chars
+- SKIP: {
+-  chdir 'toberead';
+-  open my $fh,
+-    ">floccipaucinihilopilification-"
+-   . "pneumonoultramicroscopicsilicovolcanoconiosis-"
+-   . "lopadotemachoselachogaleokranioleipsanodrimypotrimmatosilphiokarabo"
+-   . "melitokatakechymenokichlepikossyphophattoperisteralektryonoptokephal"
+-   . "liokinklopeleiolagoiosiraiobaphetraganopterygon"
+-    or
+-     chdir updir,
+-     skip("OS does not support long file names (and I mean *long*)", 1);
+-  chdir updir;
+-  opendir my $dirh, "toberead";
+-  my $test_name
+-    = "dir iterators can be cloned when the next fn > 255 chars";
+-  while() {
+-   my $pos = telldir $dirh;
+-   my $fn = readdir($dirh);
+-   if(!defined $fn) { fail($test_name); last SKIP; }
+-   if($fn =~ 'lagoio') { 
+-    seekdir $dirh, $pos;
+-    last;
+-   }
+-  }
+-  is length async { scalar readdir $dirh } ->join, 258, $test_name;
+- }
+-
+- is scalar @w, 0, 'no warnings during all that' or diag @w;
+- chdir updir;
+-}
+-rmtree($dir);
+diff --git a/win32/config.gc b/win32/config.gc
+index 271627a..87421e9 100644
+--- a/win32/config.gc
++++ b/win32/config.gc
+@@ -198,6 +198,7 @@ d_fd_macros='define'
+ d_fd_set='define'
+ d_fdclose='undef'
+ d_fdim='undef'
++d_fdopendir='undef'
+ d_fds_bits='define'
+ d_fegetround='undef'
+ d_ffs='undef'
+diff --git a/win32/config.vc b/win32/config.vc
+index ced8779..c782641 100644
+--- a/win32/config.vc
++++ b/win32/config.vc
+@@ -198,6 +198,7 @@ d_fd_macros='define'
+ d_fd_set='define'
+ d_fdclose='undef'
+ d_fdim='undef'
++d_fdopendir='undef'
+ d_fds_bits='define'
+ d_fegetround='undef'
+ d_ffs='undef'
diff -Nru perl-5.36.0/debian/patches/fixes/CVE-2025-40909-2.diff perl-5.36.0/debian/patches/fixes/CVE-2025-40909-2.diff
--- perl-5.36.0/debian/patches/fixes/CVE-2025-40909-2.diff	1970-01-01 02:00:00.000000000 +0200
+++ perl-5.36.0/debian/patches/fixes/CVE-2025-40909-2.diff	2025-08-29 15:04:15.000000000 +0300
@@ -0,0 +1,68 @@
+From: Steve Hay <steve.m.hay@googlemail.com>
+Date: Sun, 1 Jun 2025 10:37:34 +0100
+Subject: Minor corrections to 1f9097b342e0e37d619dfab6ea82ea99611b30bf
+
+(cherry picked from commit d19a96bcde20e2c6d237c843120d4a2dda0bda6e)
+
+Origin: backport, https://github.com/Perl/perl5/commit/b088e97848411fcff31efe817397985da30a664d
+Bug: https://github.com/Perl/perl5/issues/23010
+Bug-Debian: https://bugs.debian.org/1098226
+---
+ Cross/config.sh-arm-linux      | 2 +-
+ Cross/config.sh-arm-linux-n770 | 2 +-
+ config_h.SH                    | 2 +-
+ plan9/config_sh.sample         | 2 +-
+ 4 files changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/Cross/config.sh-arm-linux b/Cross/config.sh-arm-linux
+index 5297874..2118550 100644
+--- a/Cross/config.sh-arm-linux
++++ b/Cross/config.sh-arm-linux
+@@ -211,7 +211,7 @@ d_fd_macros='define'
+ d_fd_set='define'
+ d_fdclose='undef'
+ d_fdim='undef'
+-d_fdopendir=undef
++d_fdopendir='undef'
+ d_fds_bits='undef'
+ d_fegetround='define'
+ d_ffs='undef'
+diff --git a/Cross/config.sh-arm-linux-n770 b/Cross/config.sh-arm-linux-n770
+index ab5cfe9..1c92032 100644
+--- a/Cross/config.sh-arm-linux-n770
++++ b/Cross/config.sh-arm-linux-n770
+@@ -210,7 +210,7 @@ d_fd_macros='define'
+ d_fd_set='define'
+ d_fdclose='undef'
+ d_fdim='undef'
+-d_fdopendir=undef
++d_fdopendir='undef'
+ d_fds_bits='undef'
+ d_fegetround='define'
+ d_ffs='undef'
+diff --git a/config_h.SH b/config_h.SH
+index 5804966..eb57045 100755
+--- a/config_h.SH
++++ b/config_h.SH
+@@ -143,7 +143,7 @@ sed <<!GROK!THIS! >$CONFIG_H -e 's!^#undef\(.*/\)\*!/\*#define\1 \*!' -e 's!^#un
+ #$d_fcntl HAS_FCNTL		/**/
+ 
+ /* HAS_FDOPENDIR:
+- * This symbol, if defined, indicates that the fdopen routine is
++ * This symbol, if defined, indicates that the fdopendir routine is
+  * available to open a directory descriptor.
+  */
+ #$d_fdopendir HAS_FDOPENDIR		/**/
+diff --git a/plan9/config_sh.sample b/plan9/config_sh.sample
+index 4731443..65fc17c 100644
+--- a/plan9/config_sh.sample
++++ b/plan9/config_sh.sample
+@@ -211,7 +211,7 @@ d_fd_macros='undef'
+ d_fd_set='undef'
+ d_fdclose='undef'
+ d_fdim='undef'
+-d_fdopendir=undef
++d_fdopendir='undef'
+ d_fds_bits='undef'
+ d_fegetround='undef'
+ d_ffs='undef'
diff -Nru perl-5.36.0/debian/patches/fixes/CVE-2025-40909-3.diff perl-5.36.0/debian/patches/fixes/CVE-2025-40909-3.diff
--- perl-5.36.0/debian/patches/fixes/CVE-2025-40909-3.diff	1970-01-01 02:00:00.000000000 +0200
+++ perl-5.36.0/debian/patches/fixes/CVE-2025-40909-3.diff	2025-08-29 15:04:15.000000000 +0300
@@ -0,0 +1,29 @@
+From: Leon Timmermans <fawaka@gmail.com>
+Date: Mon, 9 Jun 2025 23:05:39 +0200
+Subject: Use PerlLIO_dup_cloexec in Perl_dirp_dup to set O_CLOEXEC
+
+dup doesn't mark the new descriptor as close-on-exec, which can lead to
+a descriptor leaking to the new process.
+
+(cherry picked from commit d6f09a896842e5288af5d3817756b67a919ad7ad)
+
+Origin: backport, https://github.com/Perl/perl5/commit/08dffa08a0a3822d9eaae5bd7aea9c3a5b67a3f3
+Bug: https://github.com/Perl/perl5/issues/23010
+Bug-Debian: https://bugs.debian.org/1098226
+---
+ sv.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/sv.c b/sv.c
+index 26807ce..9ee20b2 100644
+--- a/sv.c
++++ b/sv.c
+@@ -13715,7 +13715,7 @@ Perl_dirp_dup(pTHX_ DIR *const dp, CLONE_PARAMS *const param)
+ 
+     PERL_UNUSED_ARG(param);
+ 
+-    ret = fdopendir(dup(my_dirfd(dp)));
++    ret = fdopendir(PerlLIO_dup_cloexec(my_dirfd(dp)));
+ 
+ #elif defined(WIN32)
+     ret = win32_dirp_dup(dp, param);
diff -Nru perl-5.36.0/debian/patches/fixes/CVE-2025-40909-metaconfig.diff perl-5.36.0/debian/patches/fixes/CVE-2025-40909-metaconfig.diff
--- perl-5.36.0/debian/patches/fixes/CVE-2025-40909-metaconfig.diff	1970-01-01 02:00:00.000000000 +0200
+++ perl-5.36.0/debian/patches/fixes/CVE-2025-40909-metaconfig.diff	2025-08-29 15:04:15.000000000 +0300
@@ -0,0 +1,45 @@
+From: "H.Merijn Brand" <perl5@tux.freedom.nl>
+Date: Tue, 3 Jun 2025 09:20:20 +0200
+Subject: Check for fdopendir
+
+Origin: backport, https://github.com/Perl/metaconfig/commit/0a72a5cecd3e17abe67be61dd2916b6d0cb6f398
+Bug: https://github.com/Perl/perl5/issues/23010
+Bug-Debian: https://bugs.debian.org/1098226
+---
+ regen-configure/U/perl/d_fdopendir.U | 27 +++++++++++++++++++++++++++
+ 1 file changed, 27 insertions(+)
+ create mode 100644 regen-configure/U/perl/d_fdopendir.U
+
+diff --git a/regen-configure/U/perl/d_fdopendir.U b/regen-configure/U/perl/d_fdopendir.U
+new file mode 100644
+index 0000000..5d6c20c
+--- /dev/null
++++ b/regen-configure/U/perl/d_fdopendir.U
+@@ -0,0 +1,27 @@
++?RCS: Copyright (c) 2025 H.Merijn Brand
++?RCS:
++?RCS: You may redistribute only under the terms of the Artistic License,
++?RCS: as specified in the README file that comes with the distribution.
++?RCS: You may reuse parts of this distribution only within the terms of
++?RCS: that same Artistic License; a copy of which may be found at the
++?RCS: root of the source tree for dist 4.0.
++?RCS:
++?MAKE:d_fdopendir: Inlibc
++?MAKE:	-pick add $@ %<
++?S:d_fdopendir:
++?S:	This variable conditionally defines HAS_FDOPENDIR if fdopendir() is
++?S:	available to open a directory using an opened file descriptor already
++?S:	referring to that directory.
++?S:.
++?C:HAS_FDOPENDIR:
++?C:	This symbol, if defined, indicates that the fdopendir() routine is
++?C:	available to open directories using an opened file descriptor already
++?C:	referring to that directory.
++?C:.
++?H:#$d_fdopendir HAS_FDOPENDIR		/**/
++?H:.
++?LINT:set d_fdopendir
++: see if fdopendir exists
++set fdopendir d_fdopendir
++eval $inlibc
++
diff -Nru perl-5.36.0/debian/patches/fixes/CVE-2025-40909-metaconfig-update.diff perl-5.36.0/debian/patches/fixes/CVE-2025-40909-metaconfig-update.diff
--- perl-5.36.0/debian/patches/fixes/CVE-2025-40909-metaconfig-update.diff	1970-01-01 02:00:00.000000000 +0200
+++ perl-5.36.0/debian/patches/fixes/CVE-2025-40909-metaconfig-update.diff	2025-08-29 15:04:15.000000000 +0300
@@ -0,0 +1,141 @@
+From: Niko Tyni <ntyni@debian.org>
+Date: Fri, 27 Jun 2025 17:58:05 +0300
+Subject: Update generated files for fdopendir
+
+Although Configure and config_h.SH are originally generated files, they
+were changed upstream before changing the generator (metaconfig). The
+resulting orderings don't quite match.
+
+Also update uconfig* files, which are generated from config_h.SH et al.
+---
+ Configure    | 10 +++++-----
+ config_h.SH  | 13 +++++++------
+ uconfig.h    | 11 +++++++++--
+ uconfig.sh   |  1 +
+ uconfig64.sh |  1 +
+ 5 files changed, 23 insertions(+), 13 deletions(-)
+
+diff --git a/Configure b/Configure
+index 9f1ad74..d3b578a 100755
+--- a/Configure
++++ b/Configure
+@@ -13336,10 +13336,6 @@ esac
+ set i_fcntl
+ eval $setvar
+ 
+-: see if fdopendir exists
+-set fdopendir d_fdopendir
+-eval $inlibc
+-
+ : see if fork exists
+ set fork d_fork
+ eval $inlibc
+@@ -14056,6 +14052,10 @@ eval $inlibc
+ set fdim d_fdim
+ eval $inlibc
+ 
++: see if fdopendir exists
++set fdopendir d_fdopendir
++eval $inlibc
++
+ : see if fegetround exists
+ set fegetround d_fegetround
+ eval $inlibc
+@@ -24672,6 +24672,7 @@ d_fd_macros='$d_fd_macros'
+ d_fd_set='$d_fd_set'
+ d_fdclose='$d_fdclose'
+ d_fdim='$d_fdim'
++d_fdopendir='$d_fdopendir'
+ d_fds_bits='$d_fds_bits'
+ d_fegetround='$d_fegetround'
+ d_ffs='$d_ffs'
+@@ -24685,7 +24686,6 @@ d_flockproto='$d_flockproto'
+ d_fma='$d_fma'
+ d_fmax='$d_fmax'
+ d_fmin='$d_fmin'
+-d_fdopendir='$d_fdopendir'
+ d_fork='$d_fork'
+ d_fp_class='$d_fp_class'
+ d_fp_classify='$d_fp_classify'
+diff --git a/config_h.SH b/config_h.SH
+index eb57045..244d06f 100755
+--- a/config_h.SH
++++ b/config_h.SH
+@@ -142,12 +142,6 @@ sed <<!GROK!THIS! >$CONFIG_H -e 's!^#undef\(.*/\)\*!/\*#define\1 \*!' -e 's!^#un
+  */
+ #$d_fcntl HAS_FCNTL		/**/
+ 
+-/* HAS_FDOPENDIR:
+- * This symbol, if defined, indicates that the fdopendir routine is
+- * available to open a directory descriptor.
+- */
+-#$d_fdopendir HAS_FDOPENDIR		/**/
+-
+ /* HAS_FGETPOS:
+  *	This symbol, if defined, indicates that the fgetpos routine is
+  *	available to get the file position indicator, similar to ftell().
+@@ -2521,6 +2515,13 @@ sed <<!GROK!THIS! >$CONFIG_H -e 's!^#undef\(.*/\)\*!/\*#define\1 \*!' -e 's!^#un
+  */
+ #$d_fdim HAS_FDIM		/**/
+ 
++/* HAS_FDOPENDIR:
++ *	This symbol, if defined, indicates that the fdopendir() routine is
++ *	available to open directories using an opened file descriptor already
++ *	referring to that directory.
++ */
++#$d_fdopendir HAS_FDOPENDIR		/**/
++
+ /* HAS_FEGETROUND:
+  *	This symbol, if defined, indicates that the fegetround routine is
+  *	available to return the macro corresponding to the current rounding
+diff --git a/uconfig.h b/uconfig.h
+index 4ae4e96..09f4c5c 100644
+--- a/uconfig.h
++++ b/uconfig.h
+@@ -2480,6 +2480,13 @@
+  */
+ /*#define HAS_FDIM		/ **/
+ 
++/* HAS_FDOPENDIR:
++ *	This symbol, if defined, indicates that the fdopendir() routine is
++ *	available to open directories using an opened file descriptor already
++ *	referring to that directory.
++ */
++/*#define HAS_FDOPENDIR		/ **/
++
+ /* HAS_FEGETROUND:
+  *	This symbol, if defined, indicates that the fegetround routine is
+  *	available to return the macro corresponding to the current rounding
+@@ -5340,6 +5347,6 @@
+ #endif
+ 
+ /* Generated from:
+- * 87e5998978daf803d19866c43bca24d7c01dc74119650db16f8d18d83f355da9 config_h.SH
+- * 1a5fe19cbcfd68ba70230580fd344189b5c78c11b2285efd5976366e51b3257e uconfig.sh
++ * 57ecebb7fc7e3ed45e00ca0e0af53d74ad39725a0c940647d7d9c33e5d3e98b8 config_h.SH
++ * 42c09d1ec67e7ea93ad71f8dcf212ba3ba8e6be29eb8ac0520e718b83e80e78e uconfig.sh
+  * ex: set ro: */
+diff --git a/uconfig.sh b/uconfig.sh
+index 83fdd49..34f31f3 100644
+--- a/uconfig.sh
++++ b/uconfig.sh
+@@ -150,6 +150,7 @@ d_fd_macros='undef'
+ d_fd_set='undef'
+ d_fdclose='undef'
+ d_fdim='undef'
++d_fdopendir='undef'
+ d_fds_bits='undef'
+ d_fegetround='undef'
+ d_ffs='undef'
+diff --git a/uconfig64.sh b/uconfig64.sh
+index 403e00f..c887744 100644
+--- a/uconfig64.sh
++++ b/uconfig64.sh
+@@ -150,6 +150,7 @@ d_fd_macros='undef'
+ d_fd_set='undef'
+ d_fdclose='undef'
+ d_fdim='undef'
++d_fdopendir='undef'
+ d_fds_bits='undef'
+ d_fegetround='undef'
+ d_ffs='undef'
diff -Nru perl-5.36.0/debian/patches/series perl-5.36.0/debian/patches/series
--- perl-5.36.0/debian/patches/series	2025-04-12 18:16:09.000000000 +0300
+++ perl-5.36.0/debian/patches/series	2025-08-29 15:04:15.000000000 +0300
@@ -52,3 +52,9 @@
 fixes/lto-test-fix.diff
 fixes/CVE-2023-47038.diff
 fixes/CVE-2024-56406.diff
+fixes/CVE-2023-31484.diff
+fixes/CVE-2025-40909-metaconfig.diff
+fixes/CVE-2025-40909-1.diff
+fixes/CVE-2025-40909-2.diff
+fixes/CVE-2025-40909-3.diff
+fixes/CVE-2025-40909-metaconfig-update.diff
diff --git a/Configure b/Configure
index a7a64f7f3..d3b578a58 100755
--- a/Configure
+++ b/Configure
@@ -477,6 +477,7 @@ d_fd_set=''
 d_fds_bits=''
 d_fdclose=''
 d_fdim=''
+d_fdopendir=''
 d_fegetround=''
 d_ffs=''
 d_ffsl=''
@@ -14051,6 +14052,10 @@ eval $inlibc
 set fdim d_fdim
 eval $inlibc
 
+: see if fdopendir exists
+set fdopendir d_fdopendir
+eval $inlibc
+
 : see if fegetround exists
 set fegetround d_fegetround
 eval $inlibc
@@ -24667,6 +24672,7 @@ d_fd_macros='$d_fd_macros'
 d_fd_set='$d_fd_set'
 d_fdclose='$d_fdclose'
 d_fdim='$d_fdim'
+d_fdopendir='$d_fdopendir'
 d_fds_bits='$d_fds_bits'
 d_fegetround='$d_fegetround'
 d_ffs='$d_ffs'
diff --git a/Cross/config.sh-arm-linux b/Cross/config.sh-arm-linux
index f2303707b..21185506f 100644
--- a/Cross/config.sh-arm-linux
+++ b/Cross/config.sh-arm-linux
@@ -211,6 +211,7 @@ d_fd_macros='define'
 d_fd_set='define'
 d_fdclose='undef'
 d_fdim='undef'
+d_fdopendir='undef'
 d_fds_bits='undef'
 d_fegetround='define'
 d_ffs='undef'
diff --git a/Cross/config.sh-arm-linux-n770 b/Cross/config.sh-arm-linux-n770
index b1e697f17..1c92032a6 100644
--- a/Cross/config.sh-arm-linux-n770
+++ b/Cross/config.sh-arm-linux-n770
@@ -210,6 +210,7 @@ d_fd_macros='define'
 d_fd_set='define'
 d_fdclose='undef'
 d_fdim='undef'
+d_fdopendir='undef'
 d_fds_bits='undef'
 d_fegetround='define'
 d_ffs='undef'
diff --git a/Porting/Glossary b/Porting/Glossary
index 2dcb56519..4d1b320eb 100644
--- a/Porting/Glossary
+++ b/Porting/Glossary
@@ -943,6 +943,11 @@ d_fmin (d_fmin.U):
 	This variable conditionally defines the HAS_FMIN symbol, which
 	indicates to the C program that the fmin() routine is available.
 
+d_fdopendir (d_fdopendir.U):
+	This variable conditionally defines the HAS_FORK symbol, which
+	indicates that the fdopen routine is available to open a
+	directory descriptor.
+
 d_fork (d_fork.U):
 	This variable conditionally defines the HAS_FORK symbol, which
 	indicates to the C program that the fork() routine is available.
diff --git a/Porting/config.sh b/Porting/config.sh
index 91086e62a..9bc04c6aa 100644
--- a/Porting/config.sh
+++ b/Porting/config.sh
@@ -227,6 +227,7 @@ d_fd_macros='define'
 d_fd_set='define'
 d_fdclose='undef'
 d_fdim='define'
+d_fdopendir='define'
 d_fds_bits='define'
 d_fegetround='define'
 d_ffs='undef'
diff --git a/config_h.SH b/config_h.SH
index b81748331..244d06fc9 100755
--- a/config_h.SH
+++ b/config_h.SH
@@ -2515,6 +2515,13 @@ sed <<!GROK!THIS! >$CONFIG_H -e 's!^#undef\(.*/\)\*!/\*#define\1 \*!' -e 's!^#un
  */
 #$d_fdim HAS_FDIM		/**/
 
+/* HAS_FDOPENDIR:
+ *	This symbol, if defined, indicates that the fdopendir() routine is
+ *	available to open directories using an opened file descriptor already
+ *	referring to that directory.
+ */
+#$d_fdopendir HAS_FDOPENDIR		/**/
+
 /* HAS_FEGETROUND:
  *	This symbol, if defined, indicates that the fegetround routine is
  *	available to return the macro corresponding to the current rounding
diff --git a/configure.com b/configure.com
index 1ea419785..d22d6ceae 100644
--- a/configure.com
+++ b/configure.com
@@ -6213,6 +6213,7 @@ $ WC "d_fd_set='" + d_fd_set + "'"
 $ WC "d_fd_macros='define'"
 $ WC "d_fdclose='undef'"
 $ WC "d_fdim='" + d_fdim + "'"
+$ WC "d_fdopendir='undef'"
 $ WC "d_fds_bits='define'"
 $ WC "d_fegetround='undef'"
 $ WC "d_ffs='undef'"
diff --git a/cpan/CPAN/lib/CPAN/HTTP/Client.pm b/cpan/CPAN/lib/CPAN/HTTP/Client.pm
index 4fc792c26..a616fee20 100644
--- a/cpan/CPAN/lib/CPAN/HTTP/Client.pm
+++ b/cpan/CPAN/lib/CPAN/HTTP/Client.pm
@@ -32,6 +32,7 @@ sub mirror {
 
     my $want_proxy = $self->_want_proxy($uri);
     my $http = HTTP::Tiny->new(
+        verify_SSL => 1,
         $want_proxy ? (proxy => $self->{proxy}) : ()
     );
 
diff --git a/plan9/config_sh.sample b/plan9/config_sh.sample
index 02b46570c..65fc17c94 100644
--- a/plan9/config_sh.sample
+++ b/plan9/config_sh.sample
@@ -211,6 +211,7 @@ d_fd_macros='undef'
 d_fd_set='undef'
 d_fdclose='undef'
 d_fdim='undef'
+d_fdopendir='undef'
 d_fds_bits='undef'
 d_fegetround='undef'
 d_ffs='undef'
diff --git a/regen-configure/U/perl/d_fdopendir.U b/regen-configure/U/perl/d_fdopendir.U
new file mode 100644
index 000000000..5d6c20ce4
--- /dev/null
+++ b/regen-configure/U/perl/d_fdopendir.U
@@ -0,0 +1,27 @@
+?RCS: Copyright (c) 2025 H.Merijn Brand
+?RCS:
+?RCS: You may redistribute only under the terms of the Artistic License,
+?RCS: as specified in the README file that comes with the distribution.
+?RCS: You may reuse parts of this distribution only within the terms of
+?RCS: that same Artistic License; a copy of which may be found at the
+?RCS: root of the source tree for dist 4.0.
+?RCS:
+?MAKE:d_fdopendir: Inlibc
+?MAKE:	-pick add $@ %<
+?S:d_fdopendir:
+?S:	This variable conditionally defines HAS_FDOPENDIR if fdopendir() is
+?S:	available to open a directory using an opened file descriptor already
+?S:	referring to that directory.
+?S:.
+?C:HAS_FDOPENDIR:
+?C:	This symbol, if defined, indicates that the fdopendir() routine is
+?C:	available to open directories using an opened file descriptor already
+?C:	referring to that directory.
+?C:.
+?H:#$d_fdopendir HAS_FDOPENDIR		/**/
+?H:.
+?LINT:set d_fdopendir
+: see if fdopendir exists
+set fdopendir d_fdopendir
+eval $inlibc
+
diff --git a/sv.c b/sv.c
index 16bba941c..9ee20b288 100644
--- a/sv.c
+++ b/sv.c
@@ -13700,15 +13700,6 @@ Perl_dirp_dup(pTHX_ DIR *const dp, CLONE_PARAMS *const param)
 {
     DIR *ret;
 
-#if defined(HAS_FCHDIR) && defined(HAS_TELLDIR) && defined(HAS_SEEKDIR)
-    DIR *pwd;
-    const Direntry_t *dirent;
-    char smallbuf[256]; /* XXX MAXPATHLEN, surely? */
-    char *name = NULL;
-    STRLEN len = 0;
-    long pos;
-#endif
-
     PERL_UNUSED_CONTEXT;
     PERL_ARGS_ASSERT_DIRP_DUP;
 
@@ -13720,89 +13711,13 @@ Perl_dirp_dup(pTHX_ DIR *const dp, CLONE_PARAMS *const param)
     if (ret)
         return ret;
 
-#if defined(HAS_FCHDIR) && defined(HAS_TELLDIR) && defined(HAS_SEEKDIR)
+#ifdef HAS_FDOPENDIR
 
     PERL_UNUSED_ARG(param);
 
-    /* create anew */
-
-    /* open the current directory (so we can switch back) */
-    if (!(pwd = PerlDir_open("."))) return (DIR *)NULL;
-
-    /* chdir to our dir handle and open the present working directory */
-    if (fchdir(my_dirfd(dp)) < 0 || !(ret = PerlDir_open("."))) {
-        PerlDir_close(pwd);
-        return (DIR *)NULL;
-    }
-    /* Now we should have two dir handles pointing to the same dir. */
-
-    /* Be nice to the calling code and chdir back to where we were. */
-    /* XXX If this fails, then what? */
-    PERL_UNUSED_RESULT(fchdir(my_dirfd(pwd)));
+    ret = fdopendir(PerlLIO_dup_cloexec(my_dirfd(dp)));
 
-    /* We have no need of the pwd handle any more. */
-    PerlDir_close(pwd);
-
-#ifdef DIRNAMLEN
-# define d_namlen(d) (d)->d_namlen
-#else
-# define d_namlen(d) strlen((d)->d_name)
-#endif
-    /* Iterate once through dp, to get the file name at the current posi-
-       tion. Then step back. */
-    pos = PerlDir_tell(dp);
-    if ((dirent = PerlDir_read(dp))) {
-        len = d_namlen(dirent);
-        if (len > sizeof(dirent->d_name) && sizeof(dirent->d_name) > PTRSIZE) {
-            /* If the len is somehow magically longer than the
-             * maximum length of the directory entry, even though
-             * we could fit it in a buffer, we could not copy it
-             * from the dirent.  Bail out. */
-            PerlDir_close(ret);
-            return (DIR*)NULL;
-        }
-        if (len <= sizeof smallbuf) name = smallbuf;
-        else Newx(name, len, char);
-        Move(dirent->d_name, name, len, char);
-    }
-    PerlDir_seek(dp, pos);
-
-    /* Iterate through the new dir handle, till we find a file with the
-       right name. */
-    if (!dirent) /* just before the end */
-        for(;;) {
-            pos = PerlDir_tell(ret);
-            if (PerlDir_read(ret)) continue; /* not there yet */
-            PerlDir_seek(ret, pos); /* step back */
-            break;
-        }
-    else {
-        const long pos0 = PerlDir_tell(ret);
-        for(;;) {
-            pos = PerlDir_tell(ret);
-            if ((dirent = PerlDir_read(ret))) {
-                if (len == (STRLEN)d_namlen(dirent)
-                    && memEQ(name, dirent->d_name, len)) {
-                    /* found it */
-                    PerlDir_seek(ret, pos); /* step back */
-                    break;
-                }
-                /* else we are not there yet; keep iterating */
-            }
-            else { /* This is not meant to happen. The best we can do is
-                      reset the iterator to the beginning. */
-                PerlDir_seek(ret, pos0);
-                break;
-            }
-        }
-    }
-#undef d_namlen
-
-    if (name && name != smallbuf)
-        Safefree(name);
-#endif
-
-#ifdef WIN32
+#elif defined(WIN32)
     ret = win32_dirp_dup(dp, param);
 #endif
 
diff --git a/t/op/threads-dirh.t b/t/op/threads-dirh.t
index bb4bcfc14..14c399ca1 100644
--- a/t/op/threads-dirh.t
+++ b/t/op/threads-dirh.t
@@ -13,16 +13,12 @@ BEGIN {
      skip_all_if_miniperl("no dynamic loading on miniperl, no threads");
      skip_all("runs out of memory on some EBCDIC") if $ENV{PERL_SKIP_BIG_MEM_TESTS};
 
-     plan(6);
+     plan(1);
 }
 
 use strict;
 use warnings;
 use threads;
-use threads::shared;
-use File::Path;
-use File::Spec::Functions qw 'updir catdir';
-use Cwd 'getcwd';
 
 # Basic sanity check: make sure this does not crash
 fresh_perl_is <<'# this is no comment', 'ok', {}, 'crash when duping dirh';
@@ -31,101 +27,3 @@ fresh_perl_is <<'# this is no comment', 'ok', {}, 'crash when duping dirh';
    async{}->join for 1..2;
    print "ok";
 # this is no comment
-
-my $dir;
-SKIP: {
- skip "telldir or seekdir not defined on this platform", 5
-    if !$Config::Config{d_telldir} || !$Config::Config{d_seekdir};
- my $skip = sub {
-   chdir($dir);
-   chdir updir;
-   skip $_[0], 5
- };
-
- if(!$Config::Config{d_fchdir} && $^O ne "MSWin32") {
-  $::TODO = 'dir handle cloning currently requires fchdir on non-Windows platforms';
- }
-
- my @w :shared; # warnings accumulator
- local $SIG{__WARN__} = sub { push @w, $_[0] };
-
- $dir = catdir getcwd(), "thrext$$" . int rand() * 100000;
-
- rmtree($dir) if -d $dir;
- mkdir($dir);
-
- # Create a dir structure like this:
- #   $dir
- #     |
- #     `- toberead
- #            |
- #            +---- thrit
- #            |
- #            +---- rile
- #            |
- #            `---- zor
-
- chdir($dir);
- mkdir 'toberead';
- chdir 'toberead';
- {open my $fh, ">thrit" or &$skip("Cannot create file thrit")}
- {open my $fh, ">rile" or &$skip("Cannot create file rile")}
- {open my $fh, ">zor" or &$skip("Cannot create file zor")}
- chdir updir;
-
- # Then test that dir iterators are cloned correctly.
-
- opendir my $toberead, 'toberead';
- my $start_pos = telldir $toberead;
- my @first_2 = (scalar readdir $toberead, scalar readdir $toberead);
- my @from_thread = @{; async { [readdir $toberead ] } ->join };
- my @from_main = readdir $toberead;
- is join('-', sort @from_thread), join('-', sort @from_main),
-     'dir iterator is copied from one thread to another';
- like
-   join('-', "", sort(@first_2, @from_thread), ""),
-   qr/(?<!-rile)-rile-thrit-zor-(?!zor-)/i,
-  'cloned iterator iterates exactly once over everything not already seen';
-
- seekdir $toberead, $start_pos;
- readdir $toberead for 1 .. @first_2+@from_thread;
- {
-  local $::TODO; # This always passes when dir handles are not cloned.
-  is
-    async { readdir $toberead // 'undef' } ->join, 'undef',
-   'cloned dir iterator that points to the end of the directory'
-  ;
- }
-
- # Make sure the cloning code can handle file names longer than 255 chars
- SKIP: {
-  chdir 'toberead';
-  open my $fh,
-    ">floccipaucinihilopilification-"
-   . "pneumonoultramicroscopicsilicovolcanoconiosis-"
-   . "lopadotemachoselachogaleokranioleipsanodrimypotrimmatosilphiokarabo"
-   . "melitokatakechymenokichlepikossyphophattoperisteralektryonoptokephal"
-   . "liokinklopeleiolagoiosiraiobaphetraganopterygon"
-    or
-     chdir updir,
-     skip("OS does not support long file names (and I mean *long*)", 1);
-  chdir updir;
-  opendir my $dirh, "toberead";
-  my $test_name
-    = "dir iterators can be cloned when the next fn > 255 chars";
-  while() {
-   my $pos = telldir $dirh;
-   my $fn = readdir($dirh);
-   if(!defined $fn) { fail($test_name); last SKIP; }
-   if($fn =~ 'lagoio') { 
-    seekdir $dirh, $pos;
-    last;
-   }
-  }
-  is length async { scalar readdir $dirh } ->join, 258, $test_name;
- }
-
- is scalar @w, 0, 'no warnings during all that' or diag @w;
- chdir updir;
-}
-rmtree($dir);
diff --git a/uconfig.h b/uconfig.h
index 4ae4e96e4..09f4c5c13 100644
--- a/uconfig.h
+++ b/uconfig.h
@@ -2480,6 +2480,13 @@
  */
 /*#define HAS_FDIM		/ **/
 
+/* HAS_FDOPENDIR:
+ *	This symbol, if defined, indicates that the fdopendir() routine is
+ *	available to open directories using an opened file descriptor already
+ *	referring to that directory.
+ */
+/*#define HAS_FDOPENDIR		/ **/
+
 /* HAS_FEGETROUND:
  *	This symbol, if defined, indicates that the fegetround routine is
  *	available to return the macro corresponding to the current rounding
@@ -5340,6 +5347,6 @@
 #endif
 
 /* Generated from:
- * 87e5998978daf803d19866c43bca24d7c01dc74119650db16f8d18d83f355da9 config_h.SH
- * 1a5fe19cbcfd68ba70230580fd344189b5c78c11b2285efd5976366e51b3257e uconfig.sh
+ * 57ecebb7fc7e3ed45e00ca0e0af53d74ad39725a0c940647d7d9c33e5d3e98b8 config_h.SH
+ * 42c09d1ec67e7ea93ad71f8dcf212ba3ba8e6be29eb8ac0520e718b83e80e78e uconfig.sh
  * ex: set ro: */
diff --git a/uconfig.sh b/uconfig.sh
index 83fdd49ad..34f31f38a 100644
--- a/uconfig.sh
+++ b/uconfig.sh
@@ -150,6 +150,7 @@ d_fd_macros='undef'
 d_fd_set='undef'
 d_fdclose='undef'
 d_fdim='undef'
+d_fdopendir='undef'
 d_fds_bits='undef'
 d_fegetround='undef'
 d_ffs='undef'
diff --git a/uconfig64.sh b/uconfig64.sh
index 403e00fe3..c8877449d 100644
--- a/uconfig64.sh
+++ b/uconfig64.sh
@@ -150,6 +150,7 @@ d_fd_macros='undef'
 d_fd_set='undef'
 d_fdclose='undef'
 d_fdim='undef'
+d_fdopendir='undef'
 d_fds_bits='undef'
 d_fegetround='undef'
 d_ffs='undef'
diff --git a/win32/config.gc b/win32/config.gc
index 271627a2d..87421e98a 100644
--- a/win32/config.gc
+++ b/win32/config.gc
@@ -198,6 +198,7 @@ d_fd_macros='define'
 d_fd_set='define'
 d_fdclose='undef'
 d_fdim='undef'
+d_fdopendir='undef'
 d_fds_bits='define'
 d_fegetround='undef'
 d_ffs='undef'
diff --git a/win32/config.vc b/win32/config.vc
index ced877942..c78264118 100644
--- a/win32/config.vc
+++ b/win32/config.vc
@@ -198,6 +198,7 @@ d_fd_macros='define'
 d_fd_set='define'
 d_fdclose='undef'
 d_fdim='undef'
+d_fdopendir='undef'
 d_fds_bits='define'
 d_fegetround='undef'
 d_ffs='undef'

Reply to: