in reply to Revisiting Insecure dependency in mkdir while running with -T switch at ... File/Temp.pm line 542

Does this look like some obscure bug in these versions of perl?

Based on the information you've given so far, it sounds like a bug somewhere, but more likely in one of the dependent modules. As a starting point I suggest getting the module versions for yourself: usually use Some::Module; print $Some::Module::VERSION; should be enough. You may also need to check any other modules used by qw{ File::Spec File::Spec::Unix File::Temp } that could possibly be getting involved.

My first guess is that one of the modules initializes a package variable or file-scope lexical in a way that happens to taint it from one of your $pathdir calls, and tempdir() then calls into the same module in a way that causes it to use that variable.

If you're lucky you might also find something that stands out as relevant in the changelog files of the relevant packages.

  • Comment on Re: Revisiting Insecure dependency in mkdir while running with -T switch at ... File/Temp.pm line 542
  • Select or Download Code

Replies are listed 'Best First'.
Update: Simpler reproducible test case
by sidney (Acolyte) on Apr 24, 2024 at 03:46 UTC

    I figured out how to reproduce this reliably on my own VM without a CPAN tester, and was able to figure out most of what is happening. It does not need the call to tempdir to demonstrate the bug, it can be shown as an unexpectedly tainted return from canonpath.

    File:Spec is part of PathTools, which also includes Cwd. Version 3.56_01, in perl 5.22.0, added File::Spec functions in C to Cwd.xs, including the Unix version of canonpath. Version 3.62 added the line of code that causes the xs canonpath to return a tainted value if any of the inputs are tainted.

    The environment: On any Unix or Linux system install perlbrew and use it to install perl version 5.20.3 or older. I tried this on 5.20.3, 5.18.4, 5.16.3 and 5.14.3. On an OS with a recent C compiler you may need to use the workaround described in the last comment in this perlbrew bug report. Use perlbrew switch to run with that installed perl.

    If you print File::Spec->VERSION you will see that it is an old version. Run cpanm File::Spec to get the latest release.

    The bug appears to be something wonky going on when installing a version of PathTools that has an xs version of File::Spec::Unix->canonpath on top of an old perl that has only a perl version of it. Or maybe those old perls have something else wrong in the SvTAINT macro that has a subtle effect that this is revealing?

    Here is a self-contained simple example that produces the tainted return from canonpath when run in the environment set up as above. As in my original example, $pathdir has to be set to a tainted string value of an absolute pathname that exists, and the line after that has to evaluate the -d and call to the function in that order, connected in one statement by and. The sub that is in there can be anything that causes a bareword file handle (but not STDERR, STDOUT, etc.) to be compiled. It can be put before or after the other code. It doesn't have to be run, just compiled. In fact, instead of the sub you can put in a use of any module whose loading compiles a statement that contains a bareword file handle, for example use Test;. Put this code in a file and run it with perl -T

    If you change any of the required conditions, for example replace the and with a semicolon to make it two statements, and run it, you will see the proper behavior that canonpath does not return a tainted value.

    #!/usr/bin/perl -T use File::Spec; use Scalar::Util; my $pathdir = $ENV{HOME}; # tainted, existing dir, absolute path (-d $pathdir) and File::Spec->file_name_is_absolute($pathdir); my $stuff = File::Spec->canonpath("foo/bar"); print "\nerror $stuff is tainted\n" if Scalar::Util::tainted($stuff); sub foo { open(BAREWORD, "<foobar") || return; close(BAREWORD); }
Re^2: Revisiting Insecure dependency in mkdir while running with -T switch at ... File/Temp.pm line 542
by sidney (Acolyte) on Apr 21, 2024 at 23:24 UTC
    Instead of printing out VERSION, I specified in Makefile.PL that File::Temp and File::Spec are required dependencies. That causes them to be listed with their version numbers in the PREREQUISITES section of the report. They are both the latest released version, which is what I used to get the source code for the monkey patches in the test files. If you look at the carp output produced by t/a4.t you can see that File::Spec::Unix->canonpath is called with untainted data and it returns tainted data. The source code for File::Spec::Unix->canonpath is very simple and has no variables that are not declared in my. It doesn't even have any use of $1 that could have that scope problem.