It was found that perl can load modules from the current directory if not found in the module directories, via the @INC path. A local, authenticated attacker could create a specially crafted module in a writable directory and trick a user into running a perl program from that directory; if the module is not found in previous @INC paths, it will load and execute the attacker's module.
The following issue was reported by Perl upstream:
The problem relates to Perl 5 ("perl") loading modules from the includes directory array ("@INC") in which the last element is the current directory ("."). That means that, when "perl" wants to load a module (during first compilation or during lazy loading of a module in run-time), perl will look for the module in the current directory at the end, since '.' is the last include directory in its array of include directories to seek. The issue is with requiring libraries that are in "." but are not otherwise installed.
The major problem with this behavior is that it unexpectedly puts a user at risk whenever they execute any Perl scripts from a directory that is writable by other accounts on the system. For instance, if a user is logged in as root and changes directory into /tmp or an account's home directory, it is possible to now run any shell commands that are written in C, Python or Ruby without fear.
The same isn't true for any shell commands that are written in Perl, since a significant proportion of Perl scripts will execute code in the current working directory whenever they are run. For example, if a user on a shared system creates the file /tmp/Pod/Perldoc/Toterm.pm, and then I log in as root, change directory to /tmp, and run "perldoc perlrun", it will execute the code they have placed in the file.
The most severe example discovered on Debian is that apt-get will load and execute the /tmp/Log/Agent.pm file regardless of the directory it is started from since it automatically changes directory to /tmp.
This is present in perl versions 5.24 and below. We will be making additional maintenance releases of 5.24, 5.22 (current supported versions), and (as an exception, probably) 5.20 (which is no longer officially supported) which will include the fix for it.
The fix, supplied in the attached patches, is to check if the last entry of @INC is "." and if so, to remove it as an included path.
Created attachment 1178819 [details]
Created attachment 1178820 [details]
Name: the Perl project
Upstream: John Lightsey (cPanel Security Team), Todd Rinaldo (cPanel Security Team)
Created attachment 1182725 [details]
CVE-2016-1238 maint-5.22-dot-in-inc.patch v2
Created attachment 1182726 [details]
CVE-2016-1238 maint-5.24-dot-in-inc.patch v2
Upstream bug report, which remains private for now:
However, the issue is already public via other places including:
Created perl tracking bugs for this issue:
Affects: fedora-all [bug 1360425]
Please note that the fix does not fix the real cause -- having "." in Perl module search path list (@INC variable). It only patches every module bundled with upstream Perl (i.e. core modules) that loads another module which is deemed not to be delivered within upstream Perl (i.e. non-core modules).
That is instead of not having "." in the default interpreter @INC array (see last lines of "perl -V" output), it changes some modules that do something like this:
eval "require $module";
in this manner:
+ local @INC = @INC;
+ pop @INC if $INC[-1] eq '.';
eval "require $module";
That has these consequences:
(1) It does not fix any of the thousands of modules distributed from CPAN or another upstream. And many of them are delivered by Fedora.
(2) Applying the patches to perl package in Fedora will keep vulnerable Fedora packages that supersede some Perl core modules (i.e. dual-lived modules). E.g. Locale::Maketext module is delivered from perl-Locale-Maketext source package in Fedora. Not from perl source package. That means cloning this vulnerability to perl component is not enough. It should be cloned to perl-Locale-Maketext too. And probably to tens of other Fedora components.
(3) It's possible that even plain "require Foo::Bar;" code not in the eval argument possess the vulnerability in Fedora. Even if Foo::Bar were core module. That's because Foo::Bar module can be delivered by a binary package that is not required when installing package that does the "require Foo::Bar;". Either on purpose or as a packaging bug. While I consider this case as improbable (upstream worked very hard on the patches, Fedora tries to specify all dependencies between packages), I cannot exclude it.
Fedora maintainers will deliver the upstream patches as part of new perl versions 5.22.3 and 5.24.1 in the beginning of August. Fedora maintainers will patch the dual-lived modules independently.
Due to nature of this bug, Fedora maintainers are pondering removing the "." path from the default @INC globally on the perl interpreter level. At least in F26 and probably F25. And adding the "." to the specific few modules that depends on it (inc::latest, inc::Module::Install).
(In reply to Petr Pisar from comment #8)
> Please note that the fix does not fix the real cause -- having "." in Perl
> module search path list (@INC variable). It only patches every module
> bundled with upstream Perl (i.e. core modules) that loads another module
> which is deemed not to be delivered within upstream Perl (i.e. non-core
That is correct. The thing is that "." has been in @INC for way too long, and hence it's relied on, and its removal will cause breakage. The info we got indicates that upstream may proceed with removing it in the future versions, but it's quite a big change for minor release. Hence this partial and more complicated fix to address recently-discovered cases where this issue has significant impact.
I think this frankly a bad fix for the wrong problem. Removing the . may cause problems but doing it at the module level is likely to have very serious side effects. I am of the view that merely compiling a module should not have side effects. A patch suggested in most places (i.e Peter's patch above minus the dynamic scoping) adds very strange order-dependent bugs to programs. At least insisting that @INC should be localized bfore the modification helps. But changing inc just because a module was compiled strikes me as very, very bad practice and in fact I have been bitten by the order-dependent implications of the Debian approach to this "fix" already.
The problem is not that a Perl module might include stuff from the wrong directories. The problem is that a perl *script* might. So I think the security concern here is rather badly scoped. This is NOT a module vulnerability unless modules are *adding* . to the INC directory.
The right way, I think, to see this problem is that a program might not be written to address the implications of the INC directory. So if the concern is that if someone has a nightly run of prove running as root in their /tmp directory then the correct solution is to add to bin/prove:
no lib '.';
That fixes the problem nicely and far more completely than the proposed fix here does and it does so without side effects. Keeping the fix limited to scripts rather than libraries ensures that exploits are prevented and that breakage is not a real problem. Insisting that one fixes it by removing the current directory from any possible position in @INC also means it cannot be carelessly added back in by using the -I. flag.
So the proposed fix is rather overinclusive (and needlessly breaking) and underinclusive (in no way eliminating the vulnerabilities).
I will give you a good example of the problem of making this the module's responsibility: use base
Now without this sort of change, you do:
use base 'MyNamespace::Submodule';
And away you go.
With this sort of change, suddenly that breaks unless you do:
use base 'MyNamespace::Submodule';
Now you will note this ends up almost exactly equivalent except that the import() routine is run (more opportunity for malicious code if that is what you are worried about). So you haven't eliminated vulnerabilities. You have only increased annoyance.
So, really, this is best seen as a script vulnerability, not a module one. Keep concerns cleanly separated and everyone wins.
As a note, I put together a blog post which includes an exploit of this sort, how administrators can secure their systems and some general guidelines for Perl module developers. It also discusses a serious bug Debian included with their effort to fix this problem as well as recommendations for what Red Hat and others can do to help mitigate this problem.
The best option for a resolution from Red Hat would be clear guidelines on Perl module development, an auditing of existing bin/ scripts to add no lib '.' where apropriate, and an option for sysadmins to be able to remove the '.' from @INC globally on a per system basis.
But making the contents of INC the module's responsibility is a very bad idea and a system that cannot be readily understood cannot be readily secured.
In original patch, a version was renamed to an incorrect one in a single core module distribution in perl (PathTools, carrying Path::Spec)
perl-5.22.2-362.fc24 has been pushed to the Fedora 24 stable repository. If problems still persist, please make note of it in this bug report.
perl-5.22.2-354.fc23 has been pushed to the Fedora 23 stable repository. If problems still persist, please make note of it in this bug report.
I've worked out what I believe to be a mitigation for this:
Create the file CustomStartupCode.pm with the following content and place it somewhere in your @INC path (I placed it in /usr/lib/perl5/site_perl/5.8.8 for EL5):
our $VERSION = 1.00;
# CVE-2016-1238 Mitigation
pop @INC if $INC[-1] eq '.';
... Add the following to /etc/profile:
Close any open shells, open a new one and issue: perl -le 'print "@INC"'
...the resulting list should no longer have the lone "." at the end.
(In reply to Peter Ajamian from comment #21)
> I've worked out what I believe to be a mitigation for this:
> Create the file CustomStartupCode.pm with the following content and place it
> somewhere in your @INC path (I placed it in /usr/lib/perl5/site_perl/5.8.8
> for EL5):
Since RHEL-6, perl is compiled with -Dusesitecustomize option which provides /usr/local/share/perl5/sitecustomize.pl location for these system-wide initialization code. One can put the "pop @INC if $INC[-1] eq '.';" line there and then any perl invocation will execute it automatically on each Perl interpreter start-up. (One can selectively disable this feature by "-f" perl's run-time option.)
Because all the upstream patches so far fixed only core modules and even they contain controversial changes, like the "base" module lost its ability to load optional modules, I think the most conservative fix would be not to fix it at all and only document that those who feel the urge to change the behavior, they can add the line into the /usr/local/share/perl5/sitecustomize.pl file. Such change will provide complete fix for all Perl modules, including non-core or third-party modules.
(In reply to Petr Pisar from comment #22)
> Since RHEL-6, perl is compiled with -Dusesitecustomize option which provides
> /usr/local/share/perl5/sitecustomize.pl location for these system-wide
> initialization code.
Right, I only gave the above mitigation the way I did because it works in RHEL5. Certainly it is simpler to just use sitecustomize.pl for RHEL6 and 7.
Current upstream situation is this: Modules bundled with Perl are sanitized to remove the trailing '.' from @INC before loading optional modules. 'base' module was reverted to original state, i.e. it does not sanitize @INC at all. Next Perl release, 5.26.0, will not have the '.' in @INC.
When will the rpm with the real fix be released?
The real fix is not have "." in the default @INC array at all. As the removal constitutes a serious change in the behavior (e.g. it breaks 8 % of CPAN distributions <http://cpan.simcop2387.info/failed.html>), I do not believe it's reasonable to deliver this fix in a frame of already released products like RHEL-7. You can definitely count with the fix in RHEL-8 or rh-perl526 software collection.
Just to confirm, a remediation will not be provided via a patch to the package and the vendor recommended remediation for RHEL5 using Perl5 is Comment 21? Just to confirm as external auditors are asking.
Apologies, we're RHEL6 so Comment #22 but same basic confirmation that a backport fix via the package won't be be provided based on the concerns expressed in Comment #26.
The following examples will remove '.' from the module path :
RHEL6 and above :
Create a file /usr/local/share/perl5/sitecustomize.pl containing the line "pop @INC if $INC[-1] eq '.';"
Create a perl module with the same code in a BEGIN block, and use the 'PERL5OPT=-m<module-name>' environment variable to load it before execution of a perl program.