Control: tags 1087882 + patch
Control: tags 1087882 + pending

Dear maintainer,

I've prepared an NMU for needrestart (versioned as 3.8-0.1) and
uploaded it to DELAYED/10. Please feel free to tell me if I
should delay it longer.

Regards.
diff -Nru needrestart-3.7/ChangeLog needrestart-3.8/ChangeLog
--- needrestart-3.7/ChangeLog	2024-08-11 17:01:18.000000000 -0400
+++ needrestart-3.8/ChangeLog	2024-11-18 16:46:03.000000000 -0500
@@ -1,3 +1,54 @@
+needrestart 3.8
+
+  * Security:
+    - [Core] CVE-2024-48991: Prevent race condition on /proc/$PID/exec evaluation.
+      (responsibly reported by Qualys)
+    - [Interp] CVE-2024-11003: Drop usage of Module::ScanDeps to prevent LPE.
+      (responsibly reported by Qualys)
+    - [Interp] CVE-2024-48990: Do not set PYTHONPATH environment variable to prevent a LPE.
+      (responsibly reported by Qualys)
+    - [Interp] CVE-2024-48992: Do not set RUBYLIB environment variable to prevent a LPE.
+      (responsibly reported by Qualys)
+
+  * Features:
+    - [CONT] Add Incus support.
+      (github pull request #315 by Colin Watson @cjwatson)
+
+  * Changes:
+    - [Core] Refactor device number comparison to be independent of leading zeros.
+      (closes #286)
+    - [Interp] Enable ruby check for versioned ruby binary names.
+      (suggested by Qualys)
+    - [Interp] Chdir into empty directory to prevent python parsing arbitrary files.
+      (motivated by Qualys)
+
+  * Fixes:
+    - [VM] Fix spelling mistake.
+      (github pull request #309 by @fritz-fritz)
+    - [Core] Make OpenMetrics output prometheus compatible.
+      (github pull request #311 by Gabriel Filion @lelutin)
+    - [uCode] Fix error handling logic being dependent on debug level.
+      (github pull request #313 by Aristarkh Zagorodnikov @onyxmaster)
+    - [Core] Fix "Use of uninitialized value $sdev in right bitshift".
+      (github pull request #314 by Aristarkh Zagorodnikov @onyxmaster)
+
+
+  This release contains some critical security fixes in the interpreter module.
+  While the default configuration was vulnerable it is possible to migitate
+  the issues by disabling the interpeter heuristic: `$nrconf{interpscan} = 0;`
+
+  All CVEs received a CVSS core of:
+    CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H [7.8 HIGH]
+
+  Qualys Security Advisory:
+    https://www.qualys.com/2024/11/19/needrestart/needrestart.txt
+
+  Many thanks to the Qualys Security Advisory team and Mark Esler from the
+  Ubuntu Security Team for the responsible disclosure, reviewing patches and
+  coordinating the disclosure of these security issues.
+
+ -- Thomas Liske <tho...@fiasko-nw.net>  Tue, 19 Nov 2024 17:00:00 +0100
+
 needrestart 3.7
 
   * Features:
diff -Nru needrestart-3.7/debian/changelog needrestart-3.8/debian/changelog
--- needrestart-3.7/debian/changelog	2024-11-28 17:21:38.000000000 -0500
+++ needrestart-3.8/debian/changelog	2024-12-09 14:28:40.000000000 -0500
@@ -1,3 +1,19 @@
+needrestart (3.8-0.1) experimental; urgency=medium
+
+  * New upstream release (Closes: #1087882)
+  * Remove patches merged upstream
+    - 09-recognize-versioned-ruby-interpreter.diff
+    - 11-spelling-error.diff
+    - core-prevent-race-condition-on-proc-PID-exec-evaluat.patch
+    - interp-chdir-into-empty-directory-to-prevent-python-.patch
+    - interp-do-not-set-PYTHONPATH-environment-variable-to.patch
+    - interp-do-not-set-RUBYLIB-environment-variable-to-pr.patch
+    - interp-drop-usage-of-Module-ScanDeps-to-prevent-LPE.patch
+  * 08-uninitialized-vars-arm.diff kept, but rerolled, seems like upstream
+    had a different fix, might be unnecessary
+
+ -- Antoine Beaupré <anar...@debian.org>  Mon, 09 Dec 2024 14:28:40 -0500
+
 needrestart (3.7-3.3) unstable; urgency=medium
 
   * Non-maintainer upload.
diff -Nru needrestart-3.7/debian/patches/08-uninitialized-vars-arm.diff needrestart-3.8/debian/patches/08-uninitialized-vars-arm.diff
--- needrestart-3.7/debian/patches/08-uninitialized-vars-arm.diff	2024-11-28 17:21:38.000000000 -0500
+++ needrestart-3.8/debian/patches/08-uninitialized-vars-arm.diff	2024-12-09 14:28:40.000000000 -0500
@@ -2,28 +2,23 @@
 # warnings on some amd64 and arm systems.
 # Closes: #1063719
 
-diff -Naur needrestart-3.6.orig/perl/lib/NeedRestart/uCode.pm needrestart-3.6/perl/lib/NeedRestart/uCode.pm
---- needrestart-3.6.orig/perl/lib/NeedRestart/uCode.pm	2024-04-03 10:26:46.000000000 +0200
-+++ needrestart-3.6/perl/lib/NeedRestart/uCode.pm	2024-04-03 10:34:02.103311355 +0200
-@@ -152,10 +152,15 @@
+Index: b/perl/lib/NeedRestart/uCode.pm
+===================================================================
+--- a/perl/lib/NeedRestart/uCode.pm	2024-12-09 14:35:03.292806588 -0500
++++ b/perl/lib/NeedRestart/uCode.pm	2024-12-09 14:35:31.816801163 -0500
+@@ -152,6 +152,11 @@ sub nr_ucode_check {
  
          # call ucode modules
          foreach my $pkg (@PKGS) {
-+	    eval "${pkg}::nr_ucode_init();";
-+	    if ( $@ ) {
-+		print STDERR $@ if ($debug);
-+		next;
-+	    }
++            eval "${pkg}::nr_ucode_init();";
++            if ( $@ ) {
++                print STDERR $@ if ($debug);
++                next;
++            }
              my @nvars;
              eval "\@nvars = ${pkg}::nr_ucode_check_real(\$debug, \$ui, \$processors{\$pid});";
--            if ( $@ && $debug ) {
--                print STDERR $@;
-+            if ( $@ ) {
-+		print STDERR $@ if ($debug);
-                 $ui->progress_step;
-                 next;
-             }
-@@ -174,6 +179,10 @@
+             if ( $@ ) {
+@@ -175,6 +180,10 @@ sub nr_ucode_check {
  
      $ui->progress_fin;
  
diff -Nru needrestart-3.7/debian/patches/09-recognize-versioned-ruby-interpreter.diff needrestart-3.8/debian/patches/09-recognize-versioned-ruby-interpreter.diff
--- needrestart-3.7/debian/patches/09-recognize-versioned-ruby-interpreter.diff	2024-11-28 17:21:38.000000000 -0500
+++ needrestart-3.8/debian/patches/09-recognize-versioned-ruby-interpreter.diff	1969-12-31 19:00:00.000000000 -0500
@@ -1,15 +0,0 @@
-# Add patch from Helmut Grohne <hel...@subdivi.de> to detect versioned
-# ruby interpreters.
-# Closes: #1063155
-
---- needrestart-3.6.orig/perl/lib/NeedRestart/Interp/Ruby.pm
-+++ needrestart-3.6/perl/lib/NeedRestart/Interp/Ruby.pm
-@@ -42,7 +42,7 @@ sub isa {
-     my $pid = shift;
-     my $bin = shift;
- 
--    return 1 if($bin =~ m@^/usr/(local/)?bin/ruby$@);
-+    return 1 if($bin =~ m@^/usr/(local/)?bin/ruby(\d+\.\d+)?$@);
- 
-     return 0;
- }
diff -Nru needrestart-3.7/debian/patches/11-spelling-error.diff needrestart-3.8/debian/patches/11-spelling-error.diff
--- needrestart-3.7/debian/patches/11-spelling-error.diff	2024-11-28 17:21:38.000000000 -0500
+++ needrestart-3.8/debian/patches/11-spelling-error.diff	1969-12-31 19:00:00.000000000 -0500
@@ -1,15 +0,0 @@
-# Fix a spelling error in needrestart.
-# Closes: #1040673
-
-diff -Naur needrestart-3.6.orig/needrestart needrestart-3.6/needrestart
---- needrestart-3.6.orig/needrestart	2024-04-03 10:26:46.000000000 +0200
-+++ needrestart-3.6/needrestart	2024-04-03 10:54:42.819813966 +0200
-@@ -690,7 +690,7 @@
- 					}
- 				}
- 				print STDERR "$LOGPREF #$pid detected as VM guest with unknown name in group '$value'\n" if($nrconf{verbosity} > 1);
--				push(@guests, __x("'Unkown VM' with pid {pid}", pid=>$pid) );
-+				push(@guests, __x("'Unknown VM' with pid {pid}", pid=>$pid) );
- 				next;
- 			    }
- 			    elsif($value =~ m@/([^/]+\.service)$@) {
diff -Nru needrestart-3.7/debian/patches/core-prevent-race-condition-on-proc-PID-exec-evaluat.patch needrestart-3.8/debian/patches/core-prevent-race-condition-on-proc-PID-exec-evaluat.patch
--- needrestart-3.7/debian/patches/core-prevent-race-condition-on-proc-PID-exec-evaluat.patch	2024-11-28 17:21:38.000000000 -0500
+++ needrestart-3.8/debian/patches/core-prevent-race-condition-on-proc-PID-exec-evaluat.patch	1969-12-31 19:00:00.000000000 -0500
@@ -1,34 +0,0 @@
-From 99d954da8122122fa18bce061fcf2fb307135b64 Mon Sep 17 00:00:00 2001
-From: Thomas Liske <tho...@fiasko-nw.net>
-Date: Sat, 12 Oct 2024 16:05:30 +0200
-Subject: [PATCH 1/5] core: prevent race condition on /proc/$PID/exec
- evaluation
-
----
- needrestart | 5 +++++
- 1 file changed, 5 insertions(+)
-
-diff --git a/needrestart b/needrestart
-index cad58c3..d8cb9a5 100755
---- a/needrestart
-+++ b/needrestart
-@@ -530,11 +530,16 @@ if(defined($opt_l)) {
- 	# orphaned binary
- 	$restart++ if (defined($exe) && $exe =~ s/ \(deleted\)$//);  # Linux
- 	$restart++ if (defined($exe) && $exe =~ s/^\(deleted\)//);   # Linux VServer
-+	$restart++ unless(defined($ptable->{$pid}->{exec}));
- 	print STDERR "$LOGPREF #$pid uses obsolete binary $exe\n" if($restart && $nrconf{verbosity} > 1);
- 
- 	# ignore blacklisted binaries
- 	next if(grep { $exe =~ /$_/; } @{$nrconf{blacklist}});
- 
-+	# Sync $exe with the initial value from Proc:ProcessTable to prevent race
-+	# conditions in later checks.
-+	$exe = $ptable->{$pid}->{exec} if(defined($ptable->{$pid}->{exec}));
-+
- 	# read file mappings (Linux 2.0+)
- 	unless($restart) {
- 	    if(open(HMAP, '<', "/proc/$pid/maps")) {
--- 
-2.39.5
-
diff -Nru needrestart-3.7/debian/patches/interp-chdir-into-empty-directory-to-prevent-python-.patch needrestart-3.8/debian/patches/interp-chdir-into-empty-directory-to-prevent-python-.patch
--- needrestart-3.7/debian/patches/interp-chdir-into-empty-directory-to-prevent-python-.patch	2024-11-28 17:21:38.000000000 -0500
+++ needrestart-3.8/debian/patches/interp-chdir-into-empty-directory-to-prevent-python-.patch	1969-12-31 19:00:00.000000000 -0500
@@ -1,68 +0,0 @@
-From 4f78b080b4cb51b3d3ea4453333ef83ebdc3590e Mon Sep 17 00:00:00 2001
-From: Thomas Liske <tho...@fiasko-nw.net>
-Date: Sun, 3 Nov 2024 19:50:31 +0100
-Subject: [PATCH 4/5] interp: chdir into empty directory to prevent python
- parsing arbitrary files
-
----
- perl/lib/NeedRestart/Interp/Python.pm | 13 +++++++++++++
- 1 file changed, 13 insertions(+)
-
-diff --git a/perl/lib/NeedRestart/Interp/Python.pm b/perl/lib/NeedRestart/Interp/Python.pm
-index 7a7002e..96e0f24 100644
---- a/perl/lib/NeedRestart/Interp/Python.pm
-+++ b/perl/lib/NeedRestart/Interp/Python.pm
-@@ -29,11 +29,13 @@ use warnings;
- 
- use parent qw(NeedRestart::Interp);
- use Cwd qw(abs_path getcwd);
-+use File::Temp qw(tempdir);
- use Getopt::Std;
- use NeedRestart qw(:interp);
- use NeedRestart::Utils;
- 
- my $LOGPREF = '[Python]';
-+my $empty_dir;
- 
- needrestart_interp_register(__PACKAGE__, "python");
- 
-@@ -79,6 +81,14 @@ sub _scan($$$$$) {
-     }
- }
- 
-+# chdir into empty directory to prevent python parsing arbitrary files
-+sub chdir_empty() {
-+    unless(defined($empty_dir)) {
-+        $empty_dir = tempdir(CLEANUP => 1);
-+    }
-+    chdir($empty_dir);
-+}
-+
- sub source {
-     my $self = shift;
-     my $pid = shift;
-@@ -185,6 +195,7 @@ sub files {
- 
-     # use cached data if avail
-     if(exists($cache->{files}->{(__PACKAGE__)}->{$src})) {
-+	chdir($cwd);
- 	print STDERR "$LOGPREF #$pid: use cached file list\n" if($self->{debug});
- 	return %{ $cache->{files}->{(__PACKAGE__)}->{$src} };
-     }
-@@ -200,11 +211,13 @@ sub files {
-     }
- 
-     # get include path from sys.path
-+    chdir_empty();
-     my ($pyread, $pywrite) = nr_fork_pipe2($self->{debug}, $ptable->{exec}, '-');
-     print $pywrite "import sys\nprint(sys.path)\n";
-     close($pywrite);
-     my ($path) = <$pyread>;
-     close($pyread);
-+    chdir("/proc/$pid/root/$ptable->{cwd}");
- 
-     # look for module source files
-     if(defined($path)) {
--- 
-2.39.5
-
diff -Nru needrestart-3.7/debian/patches/interp-do-not-set-PYTHONPATH-environment-variable-to.patch needrestart-3.8/debian/patches/interp-do-not-set-PYTHONPATH-environment-variable-to.patch
--- needrestart-3.7/debian/patches/interp-do-not-set-PYTHONPATH-environment-variable-to.patch	2024-11-28 17:21:38.000000000 -0500
+++ needrestart-3.8/debian/patches/interp-do-not-set-PYTHONPATH-environment-variable-to.patch	1969-12-31 19:00:00.000000000 -0500
@@ -1,54 +0,0 @@
-From 4c1fa7037c54224cef1e077c5ebdc7f2cfc83799 Mon Sep 17 00:00:00 2001
-From: Thomas Liske <tho...@fiasko-nw.net>
-Date: Sat, 12 Oct 2024 18:57:39 +0200
-Subject: [PATCH 2/5] interp: do not set PYTHONPATH environment variable to
- prevent a LPE
-
----
- perl/lib/NeedRestart/Interp/Python.pm | 15 +++++++--------
- 1 file changed, 7 insertions(+), 8 deletions(-)
-
-diff --git a/perl/lib/NeedRestart/Interp/Python.pm b/perl/lib/NeedRestart/Interp/Python.pm
-index 097ac05..7a7002e 100644
---- a/perl/lib/NeedRestart/Interp/Python.pm
-+++ b/perl/lib/NeedRestart/Interp/Python.pm
-@@ -190,16 +190,16 @@ sub files {
-     }
- 
-     # prepare include path environment variable
--    my %e = nr_parse_env($pid);
-+    my @path;
-     local %ENV;
-+
-+    # get include path from env
-+    my %e = nr_parse_env($pid);
-     if(exists($e{PYTHONPATH})) {
--	$ENV{PYTHONPATH} = $e{PYTHONPATH};
--    }
--    elsif(exists($ENV{PYTHONPATH})) {
--	delete($ENV{PYTHONPATH});
-+	@path = map { "/proc/$pid/root/$_"; } split(':', $e{PYTHONPATH});
-     }
- 
--    # get include path
-+    # get include path from sys.path
-     my ($pyread, $pywrite) = nr_fork_pipe2($self->{debug}, $ptable->{exec}, '-');
-     print $pywrite "import sys\nprint(sys.path)\n";
-     close($pywrite);
-@@ -207,12 +207,11 @@ sub files {
-     close($pyread);
- 
-     # look for module source files
--    my @path;
-     if(defined($path)) {
- 	chomp($path);
- 	$path =~ s/^\['//;
- 	$path =~ s/'\$//;
--	@path = map { "/proc/$pid/root/$_"; } split("', '", $path);
-+	push(@path, map { "/proc/$pid/root/$_"; } split("', '", $path));
-     }
-     else {
- 	print STDERR "$LOGPREF #$pid: failed to retrieve include path\n" if($self->{debug});
--- 
-2.39.5
-
diff -Nru needrestart-3.7/debian/patches/interp-do-not-set-RUBYLIB-environment-variable-to-pr.patch needrestart-3.8/debian/patches/interp-do-not-set-RUBYLIB-environment-variable-to-pr.patch
--- needrestart-3.7/debian/patches/interp-do-not-set-RUBYLIB-environment-variable-to-pr.patch	2024-11-28 17:21:38.000000000 -0500
+++ needrestart-3.8/debian/patches/interp-do-not-set-RUBYLIB-environment-variable-to-pr.patch	1969-12-31 19:00:00.000000000 -0500
@@ -1,81 +0,0 @@
-From 840b750f77ff67f950528e87e87045cfa724d1eb Mon Sep 17 00:00:00 2001
-From: Thomas Liske <tho...@fiasko-nw.net>
-Date: Sun, 3 Nov 2024 20:00:03 +0100
-Subject: [PATCH 3/5] interp: do not set RUBYLIB environment variable to
- prevent a LPE
-
----
- perl/lib/NeedRestart/Interp/Ruby.pm | 25 +++++++++++++++++++------
- 1 file changed, 19 insertions(+), 6 deletions(-)
-
-diff --git a/perl/lib/NeedRestart/Interp/Ruby.pm b/perl/lib/NeedRestart/Interp/Ruby.pm
-index 29b121d..37826ff 100644
---- a/perl/lib/NeedRestart/Interp/Ruby.pm
-+++ b/perl/lib/NeedRestart/Interp/Ruby.pm
-@@ -29,11 +29,13 @@ use warnings;
- 
- use parent qw(NeedRestart::Interp);
- use Cwd qw(abs_path getcwd);
-+use File::Temp qw(tempdir);
- use Getopt::Std;
- use NeedRestart qw(:interp);
- use NeedRestart::Utils;
- 
- my $LOGPREF = '[Ruby]';
-+my $empty_dir;
- 
- needrestart_interp_register(__PACKAGE__, "ruby");
- 
-@@ -76,6 +78,14 @@ sub _scan($$$$$) {
-     }
- }
- 
-+# chdir into empty directory to prevent ruby parsing arbitrary files
-+sub chdir_empty() {
-+    unless(defined($empty_dir)) {
-+        $empty_dir = tempdir(CLEANUP => 1);
-+    }
-+    chdir($empty_dir);
-+}
-+
- sub source {
-     my $self = shift;
-     my $pid = shift;
-@@ -182,25 +192,28 @@ sub files {
- 
-     # use cached data if avail
-     if(exists($cache->{files}->{(__PACKAGE__)}->{$src})) {
-+	chdir($cwd);
- 	print STDERR "$LOGPREF #$pid: use cached file list\n" if($self->{debug});
- 	return %{ $cache->{files}->{(__PACKAGE__)}->{$src} };
-     }
- 
-     # prepare include path environment variable
--    my %e = nr_parse_env($pid);
-+    my @path;
-     local %ENV;
-+
-+    # get include path from env
-+    my %e = nr_parse_env($pid);
-     if(exists($e{RUBYLIB})) {
--	$ENV{RUBYLIB} = $e{RUBYLIB};
--    }
--    elsif(exists($ENV{RUBYLIB})) {
--	delete($ENV{RUBYLIB});
-+	@path = map { "/proc/$pid/root/$_"; } split(':', $e{RUBYLIB});
-     }
- 
-     # get include path
-+    chdir_empty();
-     my $rbread = nr_fork_pipe($self->{debug}, $ptable->{exec}, '-e', 'puts $:');
--    my @path = map { "/proc/$pid/root/$_"; } <$rbread>;
-+    push(@path, map { "/proc/$pid/root/$_"; } <$rbread>);
-     close($rbread);
-     chomp(@path);
-+    chdir("/proc/$pid/root/$ptable->{cwd}");
- 
-     my %files;
-     _scan($self->{debug}, $pid, $src, \%files, \@path);
--- 
-2.39.5
-
diff -Nru needrestart-3.7/debian/patches/interp-drop-usage-of-Module-ScanDeps-to-prevent-LPE.patch needrestart-3.8/debian/patches/interp-drop-usage-of-Module-ScanDeps-to-prevent-LPE.patch
--- needrestart-3.7/debian/patches/interp-drop-usage-of-Module-ScanDeps-to-prevent-LPE.patch	2024-11-28 17:21:38.000000000 -0500
+++ needrestart-3.8/debian/patches/interp-drop-usage-of-Module-ScanDeps-to-prevent-LPE.patch	1969-12-31 19:00:00.000000000 -0500
@@ -1,161 +0,0 @@
-From d136fce9bba7730b031bff59c609830f3e072866 Mon Sep 17 00:00:00 2001
-From: Thomas Liske <tho...@fiasko-nw.net>
-Date: Mon, 4 Nov 2024 22:29:51 +0100
-Subject: [PATCH 5/5] interp: drop usage of Module::ScanDeps to prevent LPE
-
----
- INSTALL.md                          |  1 -
- README.Interp.md                    |  9 +++-
- perl/Makefile.PL                    |  1 -
- perl/lib/NeedRestart/Interp/Perl.pm | 70 ++++++++++++++++++++---------
- 4 files changed, 57 insertions(+), 24 deletions(-)
-
-diff --git a/INSTALL.md b/INSTALL.md
-index 34ae956..fb3ae53 100644
---- a/INSTALL.md
-+++ b/INSTALL.md
-@@ -5,7 +5,6 @@ Perl
- ----
- 
- - Module::Find
--- Module::ScanDeps
- - Locale::TextDomain
- - Proc::ProcessTable
- - Sort::Naturally
-diff --git a/README.Interp.md b/README.Interp.md
-index d728404..68f8683 100644
---- a/README.Interp.md
-+++ b/README.Interp.md
-@@ -35,8 +35,13 @@ NeedRestart::Interp::Perl
- Recognized binaries:	/usr/(local/)?bin/perl
- Find source file by:	command line interpretation
- 
--We are using `Module::ScanDeps` to find used packages. This should work on
--any static loaded packages, dynamic stuff will fail.
-+The source file is scanned only for 'use' lines, other module loading
-+mechanisms will not be recognized.
-+
-+*This function used the Module::ScanDeps package to get the used Perl packages
-+until needrestart 3.7. Module::ScanDeps is not used any more as it seems not
-+to be designed to work with untrustworthy perl sources which would allow an
-+attacker to use needrestart for local privilege escalation.*
- 
- 
- NeedRestart::Interp::Python
-diff --git a/perl/Makefile.PL b/perl/Makefile.PL
-index 50cea0d..e4e274d 100644
---- a/perl/Makefile.PL
-+++ b/perl/Makefile.PL
-@@ -6,7 +6,6 @@ WriteMakefile(
-     'NAME'		=> 'NeedRestart',
-     'PREREQ_PM'		=> {
- 	Module::Find => 0,
--	Module::ScanDeps => 0,
- 	Proc::ProcessTable => 0,
- 	Sort::Naturally => 0,
- 	Term::ReadKey => 0.
-diff --git a/perl/lib/NeedRestart/Interp/Perl.pm b/perl/lib/NeedRestart/Interp/Perl.pm
-index f721980..012098b 100644
---- a/perl/lib/NeedRestart/Interp/Perl.pm
-+++ b/perl/lib/NeedRestart/Interp/Perl.pm
-@@ -32,7 +32,6 @@ use Cwd qw(abs_path getcwd);
- use Getopt::Std;
- use NeedRestart qw(:interp);
- use NeedRestart::Utils;
--use Module::ScanDeps;
- 
- my $LOGPREF = '[Perl]';
- 
-@@ -48,6 +47,41 @@ sub isa {
-     return 0;
- }
- 
-+sub _scan($$$$$) {
-+    my $debug = shift;
-+    my $pid = shift;
-+    my $src = shift;
-+    my $files = shift;
-+    my $path = shift;
-+
-+    my $fh;
-+    open($fh, '<', $src) || return;
-+    # find used modules
-+    my %modules = map {
-+	(/^\s*use\s+([a-zA-Z][\w:]+)/ ? ($1 => 1) : ())
-+    } <$fh>;
-+    close($fh);
-+
-+    # track file
-+    $files->{$src}++;
-+
-+    # scan module files
-+    if(scalar keys %modules) {
-+	foreach my $module (keys %modules) {
-+        # skip some well-known Perl pragmas
-+        next if ($module =~ /^(constant|strict|vars|v5(\.\d+)?|warnings)$/);
-+
-+	    $module =~ s@::@/@g;
-+	    $module .= '.pm';
-+
-+	    foreach my $p (@$path) {
-+		my $fn = ($p ne '' ? "$p/" : '').$module;
-+		&_scan($debug, $pid, $fn, $files, $path) if(!exists($files->{$fn}) && -r $fn && -f $fn);
-+	    }
-+	}
-+    }
-+}
-+
- sub source {
-     my $self = shift;
-     my $pid = shift;
-@@ -160,32 +194,28 @@ sub files {
-     }
- 
-     # prepare include path environment variable
--    my %e = nr_parse_env($pid);
-+    my @path;
-     local %ENV;
-+
-+    # get include path from env
-+    my %e = nr_parse_env($pid);
-     if(exists($e{PERL5LIB})) {
--	$ENV{PERL5LIB} = $e{PERL5LIB};
--    }
--    elsif(exists($ENV{PERL5LIB})) {
--	delete($ENV{PERL5LIB});
-+	@path = map { "/proc/$pid/root/$_"; } split(':', $e{PERL5LIB});
-     }
- 
--    @Module::ScanDeps::IncludeLibs = (exists($opts{I}) ? ($opts{I}) : ());
--    my $href;
--    {
--	# Silence warnings of Module::ScanDeps for dynamic loaded modules (github issue #41)
--	local $SIG{__WARN__} = sub { };
-+    # get include path from @INC
-+    my $plread = nr_fork_pipe($self->{debug}, $ptable->{exec}, '-e', 'print(join("\n", @INC));');
-+    push(@path, map { "/proc/$pid/root/$_"; } <$plread>);
-+    close($plread);
-+    chomp(@path);
- 
--	$href = scan_deps(
--	    files => [$src],
--	    recurse => 1,
--            cache_file => $self->{conf}->{cache_file},
--	    );
--    }
-+    my %files;
-+    _scan($self->{debug}, $pid, $src, \%files, \@path);
- 
-     my %ret = map {
--	my $stat = nr_stat("/proc/$pid/root/$href->{$_}->{file}");
--	$href->{$_}->{file} => ( defined($stat) ? $stat->{ctime} : undef );
--    } keys %$href;
-+	my $stat = nr_stat("/proc/$pid/root/$_");
-+	$_ => ( defined($stat) ? $stat->{ctime} : undef );
-+    } keys %files;
- 
-     chdir($cwd);
- 
--- 
-2.39.5
-
diff -Nru needrestart-3.7/debian/patches/series needrestart-3.8/debian/patches/series
--- needrestart-3.7/debian/patches/series	2024-11-28 17:21:38.000000000 -0500
+++ needrestart-3.8/debian/patches/series	2024-12-09 14:28:40.000000000 -0500
@@ -1,12 +1,5 @@
 01-use-invoke-rc-d.diff
 03-ignore-serial-getty.diff
 08-uninitialized-vars-arm.diff
-09-recognize-versioned-ruby-interpreter.diff
 10-notify-send-timeout.diff
-11-spelling-error.diff
-core-prevent-race-condition-on-proc-PID-exec-evaluat.patch
-interp-do-not-set-PYTHONPATH-environment-variable-to.patch
-interp-do-not-set-RUBYLIB-environment-variable-to-pr.patch
-interp-chdir-into-empty-directory-to-prevent-python-.patch
-interp-drop-usage-of-Module-ScanDeps-to-prevent-LPE.patch
 core-fix-regression-of-false-positives-for-processes.patch
diff -Nru needrestart-3.7/INSTALL.md needrestart-3.8/INSTALL.md
--- needrestart-3.7/INSTALL.md	2024-08-11 17:01:18.000000000 -0400
+++ needrestart-3.8/INSTALL.md	2024-11-18 16:46:03.000000000 -0500
@@ -5,7 +5,6 @@
 ----
 
 - Module::Find
-- Module::ScanDeps
 - Locale::TextDomain
 - Proc::ProcessTable
 - Sort::Naturally
diff -Nru needrestart-3.7/needrestart needrestart-3.8/needrestart
--- needrestart-3.7/needrestart	2024-08-11 17:01:18.000000000 -0400
+++ needrestart-3.8/needrestart	2024-11-18 16:46:03.000000000 -0500
@@ -472,6 +472,11 @@
     krunning => q(unknown),
     kexpected => q(unknown),
 );
+my %ometric_ucode_values = (
+    status => q(unknown),
+    current => q(unknown),
+    expected => q(unkown),
+);
 
 my %restart;
 my %sessions;
@@ -525,11 +530,16 @@
 	# orphaned binary
 	$restart++ if (defined($exe) && $exe =~ s/ \(deleted\)$//);  # Linux
 	$restart++ if (defined($exe) && $exe =~ s/^\(deleted\)//);   # Linux VServer
+	$restart++ unless(defined($ptable->{$pid}->{exec}));
 	print STDERR "$LOGPREF #$pid uses obsolete binary $exe\n" if($restart && $nrconf{verbosity} > 1);
 
 	# ignore blacklisted binaries
 	next if(grep { $exe =~ /$_/; } @{$nrconf{blacklist}});
 
+	# Sync $exe with the initial value from Proc:ProcessTable to prevent race
+	# conditions in later checks.
+	$exe = $ptable->{$pid}->{exec} if(defined($ptable->{$pid}->{exec}));
+
 	# read file mappings (Linux 2.0+)
 	unless($restart) {
 	    if(open(HMAP, '<', "/proc/$pid/maps")) {
@@ -568,27 +578,36 @@
 
 			# get on-disk info
 			my ($sdev, $sinode) = stat($testp);
+			unless($sdev) {
+			    print STDERR "$LOGPREF #$pid map stat for $testp failed: $!\n" if($nrconf{skip_mapfiles} == 0 && $nrconf{verbosity} > 1);
+			    next;
+			}
 			my @sdevs = (
 			    # glibc gnu_dev_* definition from sysmacros.h
-			    sprintf("%02x:%02x", (($sdev >> 8) & 0xfff) | (($sdev >> 32) & ~0xfff), (($sdev & 0xff) | (($sdev >> 12) & ~0xff))),
+			    sprintf("%x:%x", (($sdev >> 8) & 0xfff) | (($sdev >> 32) & ~0xfff), ($sdev & 0xff) | (($sdev >> 12) & ~0xff)),
 			    # Traditional definition of major(3) and minor(3)
-			    sprintf("%02x:%02x", $sdev >> 8, $sdev & 0xff),
+			    sprintf("%x:%x", $sdev >> 8, $sdev & 0xff),
 
 			    # kFreeBSD: /proc/<pid>/maps does not contain device IDs
-			    qq(00:00)
+			    qq(0:0)
 			    );
 
 			# Don't compare device numbers on anon filesystems
 			# w/o a backing device (like OpenVZ's simfs).
 			my $major = (($sdev >> 8) & 0xfff) | (($sdev >> 32) & ~0xfff);
-			$mdev = "00:00"
-			    if ($major == 0 || $major == 144 || $major == 145 || $major == 146);
+			if ($major == 0 || $major == 144 || $major == 145 || $major == 146) {
+			    $mdev = "0:0";
+			}
+			else {
+			    # strip leading zeros
+			    $mdev =~ s/(^|:)0+([\da-f]+)/$1$2/g;
+			}
 
 			# compare maps content vs. on-disk
 			unless($minode eq $sinode && ((grep {$mdev eq $_} @sdevs) ||
 						      # BTRFS breaks device ID mapping completely...
 						      # ignoring unnamed device IDs for now
-						      $mdev =~ /^00:/)) {
+						      $mdev =~ /^0:/)) {
 			    print STDERR "$LOGPREF #$pid uses obsolete $path\n" if($nrconf{verbosity} > 1);
 			    $restart++;
 			    last;
@@ -712,7 +731,7 @@
 					}
 				}
 				print STDERR "$LOGPREF #$pid detected as VM guest with unknown name in group '$value'\n" if($nrconf{verbosity} > 1);
-				push(@guests, __x("'Unkown VM' with pid {pid}", pid=>$pid) );
+				push(@guests, __x("'Unknown VM' with pid {pid}", pid=>$pid) );
 				next;
 			    }
 			    elsif($value =~ m@/([^/]+\.service)$@) {
@@ -910,7 +929,12 @@
             }
         }
         elsif ($opt_o) {
-            $ometric_kernel_values{kresult} = $kresult;
+	    my %kernel_states = (
+		&NRK_NOUPGRADE => "current",
+		&NRK_ABIUPGRADE => "abi_upgrade",
+		&NRK_VERUPGRADE => "version_upgrade",
+	    );
+            $ometric_kernel_values{kresult} = $kernel_states{$kresult};
             $ometric_kernel_values{krunning} = $kvars{KVERSION};
             $ometric_kernel_values{kexpected} = $kvars{EVERSION};
         }
@@ -969,23 +993,35 @@
             }
 	    }
         else {
-            if($ucode_result == NRM_OBSOLETE) {
-                $nagios{mstr} = "OBSOLETE";
-                $nagios{mret} = $nrconf{q(nagios-status)}->{ucode};
-                $nagios{mperf} = 1;
-            }
-            elsif($ucode_result == NRM_CURRENT) {
-                $nagios{mstr} = "CURRENT";
-                $nagios{mret} = 0;
-                $nagios{mperf} = 0;
-            }
-
-            if($nagios{mret} == 1) {
-                $nagios{mstr} .= " (!)";
-            }
-            elsif($nagios{mret} == 2) {
-                $nagios{mstr} .= " (!!)";
-            }
+	    if ($opt_p) {
+		if($ucode_result == NRM_OBSOLETE) {
+		    $nagios{mstr} = "OBSOLETE";
+		    $nagios{mret} = $nrconf{q(nagios-status)}->{ucode};
+		    $nagios{mperf} = 1;
+		}
+		elsif($ucode_result == NRM_CURRENT) {
+		    $nagios{mstr} = "CURRENT";
+		    $nagios{mret} = 0;
+		    $nagios{mperf} = 0;
+		}
+
+		if($nagios{mret} == 1) {
+		    $nagios{mstr} .= " (!)";
+		}
+		elsif($nagios{mret} == 2) {
+		    $nagios{mstr} .= " (!!)";
+		}
+	    }
+	    elsif ($opt_o) {
+		my %ucode_states = (
+		    &NRM_CURRENT => "current",
+		    &NRM_OBSOLETE => "obsolete",
+		    &NRM_UNKNOWN => "unknown",
+		);
+		$ometric_ucode_values{status} = $ucode_states{$ucode_result};
+		$ometric_ucode_values{current} = $ucode_result != NRM_UNKNOWN ? $ucode_vars{CURRENT} : "unknown";
+		$ometric_ucode_values{expected} = $ucode_result != NRM_UNKNOWN ? $ucode_vars{AVAIL} : "unknown";
+	    }
         }
 	}
 	else {
@@ -1426,33 +1462,25 @@
     exit $ret;
 }
 if ($opt_o) {
-    print "# TYPE needrestart_build info\n";
-    print "# HELP needrestart_build information about needrestart's runtime build\n";
-    print "needrestart_build_info{version=$NeedRestart::VERSION,perl_version=$^V} 1\n";
+    print "# TYPE needrestart_build_info gauge\n";
+    print "# HELP needrestart_build_info information about needrestart's runtime build\n";
+    print "needrestart_build_info{version=\"$NeedRestart::VERSION\",perl_version=\"$^V\"} 1\n";
 
     if ($opt_k) {
-        my @ometric_kernel_status = map { $_ == $ometric_kernel_values{kresult} ? 1 : 0 } (NRK_NOUPGRADE, NRK_ABIUPGRADE, NRK_VERUPGRADE);
-        print "# TYPE needrestart_kernel_status stateset\n";
+        print "# TYPE needrestart_kernel_status gauge\n";
         print "# HELP needrestart_kernel_status status of kernel as reported by needrestart\n";
-        print "needrestart_kernel_status{needrestart_kernel_status=\"current\"} $ometric_kernel_status[0]\n";
-        print "needrestart_kernel_status{needrestart_kernel_status=\"abi_upgrade\"} $ometric_kernel_status[1]\n";
-        print "needrestart_kernel_status{needrestart_kernel_status=\"version_upgrade\"} $ometric_kernel_status[2]\n";
-	print "# TYPE needrestart_kernel info\n";
-	print "# HELP needrestart_kernel version information for currenly running and most up to date kernels\n";
-	print "needrestart_kernel_info{running=\"$ometric_kernel_values{krunning}\",expected=\"$ometric_kernel_values{kexpected}\"} 1\n";
+        print "needrestart_kernel_status{needrestart_kernel_status=\"$ometric_kernel_values{kresult}\"} 1\n";
+	print "# TYPE needrestart_kernel_info gauge\n";
+	print "# HELP needrestart_kernel_info version information for currenly running and most up to date kernels\n";
+	print "needrestart_kernel{running=\"$ometric_kernel_values{krunning}\",expected=\"$ometric_kernel_values{kexpected}\"} 1\n";
     }
     if ($opt_w) {
-        my $ometric_ucode_current = $ucode_result != NRM_UNKNOWN ? $ucode_vars{CURRENT} : "unknown";
-        my $ometric_ucode_expected = $ucode_result != NRM_UNKNOWN ? $ucode_vars{AVAIL} : "unknown";
-        my @ometric_ucode_status = map { $_ == $ucode_result ? 1 : 0 } (NRM_CURRENT, NRM_OBSOLETE, NRM_UNKNOWN);
-        print "# TYPE needrestart_ucode_status stateset\n";
+        print "# TYPE needrestart_ucode_status gauge\n";
         print "# HELP needrestart_ucode_status status of the host's CPU microcode as reported by needrestart\n";
-        print "needrestart_ucode_status{needrestart_ucode_status=\"current\"} $ometric_ucode_status[0]\n";
-        print "needrestart_ucode_status{needrestart_ucode_status=\"obsolete\"} $ometric_ucode_status[1]\n";
-        print "needrestart_ucode_status{needrestart_ucode_status=\"unknown\"} $ometric_ucode_status[2]\n";
-	print "# TYPE needrestart_ucode info\n";
-	print "# HELP needrestart_ucode version informaion for currently used and available microcode\n";
-	print "needrestart_ucode_info{running=\"$ometric_ucode_current\",expected=\"$ometric_ucode_expected\"} 1\n";
+        print "needrestart_ucode_status{needrestart_ucode_status=\"$ometric_ucode_values{status}\"} 1\n";
+	print "# TYPE needrestart_ucode_info gauge\n";
+	print "# HELP needrestart_ucode_info version informaion for currently used and available microcode\n";
+	print "needrestart_ucode{running=\"$ometric_ucode_values{current}\",expected=\"$ometric_ucode_values{expected}\"} 1\n";
     }
     if ($opt_l) {
         my $ometric_num_services = scalar %restart;
diff -Nru needrestart-3.7/perl/lib/NeedRestart/CONT/LXC.pm needrestart-3.8/perl/lib/NeedRestart/CONT/LXC.pm
--- needrestart-3.7/perl/lib/NeedRestart/CONT/LXC.pm	2024-08-11 17:01:18.000000000 -0400
+++ needrestart-3.8/perl/lib/NeedRestart/CONT/LXC.pm	2024-11-18 16:46:03.000000000 -0500
@@ -50,6 +50,10 @@
 	$self->{lxd_bin} = q(/snap/bin/lxc);
 	$self->{lxd_container_path} = q(/var/snap/lxd/common/lxd/containers);
 	print STDERR "$LOGPREF LXD installed via snap\n" if($self->{debug});
+    } elsif (-x q(/usr/bin/incus)) {
+	$self->{has_lxd} = 1;
+	$self->{lxd_bin} = q(/usr/bin/incus);
+	$self->{lxd_container_path} = q(/var/lib/incus/containers);
     } else {
 	$self->{has_lxd} = -x q(/usr/bin/lxc);
 	$self->{lxd_bin} = q(/usr/bin/lxc);
diff -Nru needrestart-3.7/perl/lib/NeedRestart/Interp/Perl.pm needrestart-3.8/perl/lib/NeedRestart/Interp/Perl.pm
--- needrestart-3.7/perl/lib/NeedRestart/Interp/Perl.pm	2024-08-11 17:01:18.000000000 -0400
+++ needrestart-3.8/perl/lib/NeedRestart/Interp/Perl.pm	2024-11-18 16:46:03.000000000 -0500
@@ -32,7 +32,6 @@
 use Getopt::Std;
 use NeedRestart qw(:interp);
 use NeedRestart::Utils;
-use Module::ScanDeps;
 
 my $LOGPREF = '[Perl]';
 
@@ -48,6 +47,41 @@
     return 0;
 }
 
+sub _scan($$$$$) {
+    my $debug = shift;
+    my $pid = shift;
+    my $src = shift;
+    my $files = shift;
+    my $path = shift;
+
+    my $fh;
+    open($fh, '<', $src) || return;
+    # find used modules
+    my %modules = map {
+	(/^\s*use\s+([a-zA-Z][\w:]+)/ ? ($1 => 1) : ())
+    } <$fh>;
+    close($fh);
+
+    # track file
+    $files->{$src}++;
+
+    # scan module files
+    if(scalar keys %modules) {
+	foreach my $module (keys %modules) {
+        # skip some well-known Perl pragmas
+        next if ($module =~ /^(constant|strict|vars|v5(\.\d+)?|warnings)$/);
+
+	    $module =~ s@::@/@g;
+	    $module .= '.pm';
+
+	    foreach my $p (@$path) {
+		my $fn = ($p ne '' ? "$p/" : '').$module;
+		&_scan($debug, $pid, $fn, $files, $path) if(!exists($files->{$fn}) && -r $fn && -f $fn);
+	    }
+	}
+    }
+}
+
 sub source {
     my $self = shift;
     my $pid = shift;
@@ -160,32 +194,28 @@
     }
 
     # prepare include path environment variable
-    my %e = nr_parse_env($pid);
+    my @path;
     local %ENV;
+
+    # get include path from env
+    my %e = nr_parse_env($pid);
     if(exists($e{PERL5LIB})) {
-	$ENV{PERL5LIB} = $e{PERL5LIB};
-    }
-    elsif(exists($ENV{PERL5LIB})) {
-	delete($ENV{PERL5LIB});
+	@path = map { "/proc/$pid/root/$_"; } split(':', $e{PERL5LIB});
     }
 
-    @Module::ScanDeps::IncludeLibs = (exists($opts{I}) ? ($opts{I}) : ());
-    my $href;
-    {
-	# Silence warnings of Module::ScanDeps for dynamic loaded modules (github issue #41)
-	local $SIG{__WARN__} = sub { };
+    # get include path from @INC
+    my $plread = nr_fork_pipe($self->{debug}, $ptable->{exec}, '-e', 'print(join("\n", @INC));');
+    push(@path, map { "/proc/$pid/root/$_"; } <$plread>);
+    close($plread);
+    chomp(@path);
 
-	$href = scan_deps(
-	    files => [$src],
-	    recurse => 1,
-            cache_file => $self->{conf}->{cache_file},
-	    );
-    }
+    my %files;
+    _scan($self->{debug}, $pid, $src, \%files, \@path);
 
     my %ret = map {
-	my $stat = nr_stat("/proc/$pid/root/$href->{$_}->{file}");
-	$href->{$_}->{file} => ( defined($stat) ? $stat->{ctime} : undef );
-    } keys %$href;
+	my $stat = nr_stat("/proc/$pid/root/$_");
+	$_ => ( defined($stat) ? $stat->{ctime} : undef );
+    } keys %files;
 
     chdir($cwd);
 
diff -Nru needrestart-3.7/perl/lib/NeedRestart/Interp/Python.pm needrestart-3.8/perl/lib/NeedRestart/Interp/Python.pm
--- needrestart-3.7/perl/lib/NeedRestart/Interp/Python.pm	2024-08-11 17:01:18.000000000 -0400
+++ needrestart-3.8/perl/lib/NeedRestart/Interp/Python.pm	2024-11-18 16:46:03.000000000 -0500
@@ -29,11 +29,13 @@
 
 use parent qw(NeedRestart::Interp);
 use Cwd qw(abs_path getcwd);
+use File::Temp qw(tempdir);
 use Getopt::Std;
 use NeedRestart qw(:interp);
 use NeedRestart::Utils;
 
 my $LOGPREF = '[Python]';
+my $empty_dir;
 
 needrestart_interp_register(__PACKAGE__, "python");
 
@@ -79,6 +81,14 @@
     }
 }
 
+# chdir into empty directory to prevent python parsing arbitrary files
+sub chdir_empty() {
+    unless(defined($empty_dir)) {
+        $empty_dir = tempdir(CLEANUP => 1);
+    }
+    chdir($empty_dir);
+}
+
 sub source {
     my $self = shift;
     my $pid = shift;
@@ -185,34 +195,36 @@
 
     # use cached data if avail
     if(exists($cache->{files}->{(__PACKAGE__)}->{$src})) {
+	chdir($cwd);
 	print STDERR "$LOGPREF #$pid: use cached file list\n" if($self->{debug});
 	return %{ $cache->{files}->{(__PACKAGE__)}->{$src} };
     }
 
     # prepare include path environment variable
-    my %e = nr_parse_env($pid);
+    my @path;
     local %ENV;
+
+    # get include path from env
+    my %e = nr_parse_env($pid);
     if(exists($e{PYTHONPATH})) {
-	$ENV{PYTHONPATH} = $e{PYTHONPATH};
-    }
-    elsif(exists($ENV{PYTHONPATH})) {
-	delete($ENV{PYTHONPATH});
+	@path = map { "/proc/$pid/root/$_"; } split(':', $e{PYTHONPATH});
     }
 
-    # get include path
+    # get include path from sys.path
+    chdir_empty();
     my ($pyread, $pywrite) = nr_fork_pipe2($self->{debug}, $ptable->{exec}, '-');
     print $pywrite "import sys\nprint(sys.path)\n";
     close($pywrite);
     my ($path) = <$pyread>;
     close($pyread);
+    chdir("/proc/$pid/root/$ptable->{cwd}");
 
     # look for module source files
-    my @path;
     if(defined($path)) {
 	chomp($path);
 	$path =~ s/^\['//;
 	$path =~ s/'\$//;
-	@path = map { "/proc/$pid/root/$_"; } split("', '", $path);
+	push(@path, map { "/proc/$pid/root/$_"; } split("', '", $path));
     }
     else {
 	print STDERR "$LOGPREF #$pid: failed to retrieve include path\n" if($self->{debug});
diff -Nru needrestart-3.7/perl/lib/NeedRestart/Interp/Ruby.pm needrestart-3.8/perl/lib/NeedRestart/Interp/Ruby.pm
--- needrestart-3.7/perl/lib/NeedRestart/Interp/Ruby.pm	2024-08-11 17:01:18.000000000 -0400
+++ needrestart-3.8/perl/lib/NeedRestart/Interp/Ruby.pm	2024-11-18 16:46:03.000000000 -0500
@@ -29,11 +29,13 @@
 
 use parent qw(NeedRestart::Interp);
 use Cwd qw(abs_path getcwd);
+use File::Temp qw(tempdir);
 use Getopt::Std;
 use NeedRestart qw(:interp);
 use NeedRestart::Utils;
 
 my $LOGPREF = '[Ruby]';
+my $empty_dir;
 
 needrestart_interp_register(__PACKAGE__, "ruby");
 
@@ -42,7 +44,7 @@
     my $pid = shift;
     my $bin = shift;
 
-    return 1 if($bin =~ m@^/usr/(local/)?bin/ruby$@);
+    return 1 if($bin =~ m@^/usr/(local/)?bin/ruby(\d[.\d]*)?$@);
 
     return 0;
 }
@@ -76,6 +78,14 @@
     }
 }
 
+# chdir into empty directory to prevent ruby parsing arbitrary files
+sub chdir_empty() {
+    unless(defined($empty_dir)) {
+        $empty_dir = tempdir(CLEANUP => 1);
+    }
+    chdir($empty_dir);
+}
+
 sub source {
     my $self = shift;
     my $pid = shift;
@@ -182,25 +192,28 @@
 
     # use cached data if avail
     if(exists($cache->{files}->{(__PACKAGE__)}->{$src})) {
+	chdir($cwd);
 	print STDERR "$LOGPREF #$pid: use cached file list\n" if($self->{debug});
 	return %{ $cache->{files}->{(__PACKAGE__)}->{$src} };
     }
 
     # prepare include path environment variable
-    my %e = nr_parse_env($pid);
+    my @path;
     local %ENV;
+
+    # get include path from env
+    my %e = nr_parse_env($pid);
     if(exists($e{RUBYLIB})) {
-	$ENV{RUBYLIB} = $e{RUBYLIB};
-    }
-    elsif(exists($ENV{RUBYLIB})) {
-	delete($ENV{RUBYLIB});
+	@path = map { "/proc/$pid/root/$_"; } split(':', $e{RUBYLIB});
     }
 
     # get include path
+    chdir_empty();
     my $rbread = nr_fork_pipe($self->{debug}, $ptable->{exec}, '-e', 'puts $:');
-    my @path = map { "/proc/$pid/root/$_"; } <$rbread>;
+    push(@path, map { "/proc/$pid/root/$_"; } <$rbread>);
     close($rbread);
     chomp(@path);
+    chdir("/proc/$pid/root/$ptable->{cwd}");
 
     my %files;
     _scan($self->{debug}, $pid, $src, \%files, \@path);
diff -Nru needrestart-3.7/perl/lib/NeedRestart/uCode.pm needrestart-3.8/perl/lib/NeedRestart/uCode.pm
--- needrestart-3.7/perl/lib/NeedRestart/uCode.pm	2024-08-11 17:01:18.000000000 -0400
+++ needrestart-3.8/perl/lib/NeedRestart/uCode.pm	2024-11-18 16:46:03.000000000 -0500
@@ -154,8 +154,9 @@
         foreach my $pkg (@PKGS) {
             my @nvars;
             eval "\@nvars = ${pkg}::nr_ucode_check_real(\$debug, \$ui, \$processors{\$pid});";
-            if ( $@ && $debug ) {
-                print STDERR $@;
+            if ( $@ ) {
+                print STDERR $@
+                    if ($debug);
                 $ui->progress_step;
                 next;
             }
diff -Nru needrestart-3.7/perl/lib/NeedRestart.pm needrestart-3.8/perl/lib/NeedRestart.pm
--- needrestart-3.7/perl/lib/NeedRestart.pm	2024-08-11 17:01:18.000000000 -0400
+++ needrestart-3.8/perl/lib/NeedRestart.pm	2024-11-18 16:46:03.000000000 -0500
@@ -81,7 +81,7 @@
     )],
 );
 
-our $VERSION = '3.7';
+our $VERSION = '3.8';
 my $LOGPREF = '[Core]';
 
 my %UIs;
diff -Nru needrestart-3.7/perl/Makefile.PL needrestart-3.8/perl/Makefile.PL
--- needrestart-3.7/perl/Makefile.PL	2024-08-11 17:01:18.000000000 -0400
+++ needrestart-3.8/perl/Makefile.PL	2024-11-18 16:46:03.000000000 -0500
@@ -6,7 +6,6 @@
     'NAME'		=> 'NeedRestart',
     'PREREQ_PM'		=> {
 	Module::Find => 0,
-	Module::ScanDeps => 0,
 	Proc::ProcessTable => 0,
 	Sort::Naturally => 0,
 	Term::ReadKey => 0.
diff -Nru needrestart-3.7/README.Cont.md needrestart-3.8/README.Cont.md
--- needrestart-3.7/README.Cont.md	2024-08-11 17:01:18.000000000 -0400
+++ needrestart-3.8/README.Cont.md	2024-11-18 16:46:03.000000000 -0500
@@ -27,7 +27,9 @@
 `lxc-stop --reboot --name $NAME`.
 
 This package also supports LXD containers, which are restarted by `lxc restart
-$NAME` or `lxc restart --project=$PROJECT $NAME` for containers in projects.
+$NAME` or `lxc restart --project=$PROJECT $NAME` for containers in projects,
+and Incus containers, which are restarted by `incus restart $NAME` or `incus
+restart --project=$PROJECT $NAME` for containers in projects.
 
 NeedRestart::CONT::machined
 ---------------------------
diff -Nru needrestart-3.7/README.Interp.md needrestart-3.8/README.Interp.md
--- needrestart-3.7/README.Interp.md	2024-08-11 17:01:18.000000000 -0400
+++ needrestart-3.8/README.Interp.md	2024-11-18 16:46:03.000000000 -0500
@@ -35,8 +35,13 @@
 Recognized binaries:	/usr/(local/)?bin/perl
 Find source file by:	command line interpretation
 
-We are using `Module::ScanDeps` to find used packages. This should work on
-any static loaded packages, dynamic stuff will fail.
+The source file is scanned only for 'use' lines, other module loading
+mechanisms will not be recognized.
+
+*This function used the Module::ScanDeps package to get the used Perl packages
+until needrestart 3.7. Module::ScanDeps is not used any more as it seems not
+to be designed to work with untrustworthy perl sources which would allow an
+attacker to use needrestart for local privilege escalation.*
 
 
 NeedRestart::Interp::Python

Attachment: signature.asc
Description: PGP signature

Reply via email to