http://qs321.pair.com?node_id=11134553

Bod has asked for the wisdom of the Perl Monks concerning the following question:

Following the excellent advice I received over in 11134028, I have restructured the webserver for the project I have just started. The directory structure is something like this:

/home/myusername/website/prod/www <- webroot /home/myusername/website/prod/lib <- scripts /home/myusername/website/prod/template <- you can guess :) /home/myusername/website/test/data
So I have a script index.pl in the webroot which is the default when the server provides a page to a browser.
index.pl uses Site::HTML which is located at /home/myusername/website/prod/lib/Site/HTML.pm

Everything works as expected. Templates are working and scripts are called as expected. Until I turn on taint mode. Then I get this error:

Insecure dependency in require while running with -T switch at index.p +l line 8. BEGIN failed--compilation aborted at index.pl line 8.
This is the start of index.pl:
#!/usr/bin/perl -T use CGI::Carp qw(fatalsToBrowser); use FindBin qw($RealBin); use lib "$RealBin/../lib"; use Site::HTML; <-- line 8 use Site::Wayfinder; use strict; use warnings; my $html = Site::HTML->new; $html->head;
Am I right that the error I get means that Site::HTML won't work under taint mode?
Any suggestions for debugging where the problem might be in Site::HTML as the error doesn't tell me where in the module to look?

I've deliberately not shared the code of Site::HTML as I would prefer to understand how to debug this problem rather than just being given the answer of what is wrong in that module. Happy to share some of the module if necessary...

Replies are listed 'Best First'.
Re: Debugging a module that's failing under taint mode
by kcott (Archbishop) on Jul 01, 2021 at 21:47 UTC

    G'day Bod,

    ++ for seeking general understanding and guidance rather than putting your hand out for a specific solution.

    As a general rule, you should be checking for taintedness in your module's tests, rather than discovering it later when you use the module. Given a module, Some::Module, which lives in /path/to/Some-Module/, I would typically have something very close to this as my first test (/path/to/Some-Module/t/00-load.t):

    #!perl -T use strict; use warnings; use Test::More tests => 1; BEGIN { use_ok('Some::Module') } diag "Testing Some::Module $Some::Module::VERSION";

    — Ken

      As a general rule, you should be checking for taintedness in your module's tests, rather than discovering it later when you use the module

      Would you be writing tests for a single purpose module?
      In other words, a module that only ever gets used with the same 3 related scripts.

        Would you be writing tests for a single purpose module?

        Dear Bod, we've discussed this topic before, on April 1 2021 - where my answer was not intended as an April Fools' joke. In summary:

        You should write your tests before you write your module - or while you are developing it
        This is because the act of writing the tests improves the module's design, especially its interface.

        Would you be writing tests for a single purpose module? In other words, a module that only ever gets used with the same 3 related scripts.

        Yes, with 100% certainty I would.

        Besides, "only ever gets used with" are famous last words.

        I write tests for every single module I create. That includes personal and $work modules. And the first one is always 00-load.t.

        Writing tests is extremely important — I can't stress this strongly enough.

        Run 'make test' every time you change Module.pm; that provides a regression test. Now write one or more new tests that address whatever changes you made. If you're only changing a test, or want more specific feedback from a test, use 'prove -vb t/whatever.t'.

        It might seem like extra work but, in the long run, it will save you much time and frustration. If you use something like Module::Starter, some tests will be automatically written for you; you can write generic test templates which you copy to 't/' and then just do a global substitution, e.g. s/___MODULE_NAME___/Module::Name/g; you can write boilerplate tests which you can just copy and leave as is (see 't/99-02_manifest.t' in "Re: Perl tools for making code better" for an example — that's the first block of code; the filename is mentioned further down).

        I absolutely concur with ++stevieb's "famous last words" comment.

        — Ken

Re: Debugging a module that's failing under taint mode
by LanX (Saint) on Jul 01, 2021 at 21:16 UTC
    I think you need to untaint $RealBin before adding it to lib.

    > I would prefer to understand how to debug this problem

    binary search debugging:

    your problem starts already in line 8, so successively exclude half of the preceding lines, till you isolated the problem.

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery

      > I think you need to untaint $RealBin before adding it to lib.

      yep this works for me

      D:\tmp\pm>type findbin_taint.pl use strict; use warnings; use FindBin qw($RealBin); my $my_lib; BEGIN { $RealBin =~ m/(.+)/; # just a demo, +you should only accept a safe path $my_lib = "$1/../lib"; } use lib $my_lib; print join"\n",@INC; use PadWalker; # no matter wha +t you use will fail if @INC has a tainted entry D:\tmp\pm>perl -T findbin_taint.pl D:/tmp/pm/../lib C:/Strawberry/perl/site/lib/MSWin32-x64-multi-thread C:/Strawberry/perl/site/lib C:/Strawberry/perl/vendor/lib C:/Strawberry/perl/lib D:\tmp\pm>

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery

        yep this works for me

        Thanks.

        Based on the above I now have this:

        #!/usr/bin/perl -T use CGI::Carp qw(fatalsToBrowser); use FindBin qw($RealBin); my $safepath; BEGIN { if ($RealBin =~ m!^(/home/username/website/uk/www)!) { $safepath = "$1/../lib"; } else { die "Illegal use of software - visit www.website.uk to use thi +s site"; } } use lib "$RealBin/../lib"; use Site::HTML; <-- line 17
        This gives the same error Insecure dependency in require while running with -T switch at index.pl line 18. so I think I can safely assume that the problem is with the Site::HTML module.

        Edit:

        Whoops! Above I left it as use lib "$RealBin/../lib";
        Changing it to use lib "$safepath"; works.

        So, at least I know Site::HTML can be used with taint mode. Now to find where it doesn't function.

Re: Debugging a module that's failing under taint mode
by hippo (Bishop) on Jul 01, 2021 at 21:52 UTC
      We've already been through this...

      I'm not sure we have. Or if we have, I am just not understanding how to use taint mode.

      11134033 was about getting the paths right. I am pretty sure that I've now got that right. This is about debugging the module that I am trying to use. As the module is one I have written, I cannot be at all sure that it is going to work under taint mode.

      Edit

      The wisdom of hippo has been proved.
      It was about paths, I just thought it was about debugging a module...

Re: Debugging a module that's failing under taint mode
by GrandFather (Saint) on Jul 01, 2021 at 21:26 UTC

    Is there some reason you can't run the code under the debugger or, even better, use an IDE such as Komodo? You can require the module instead of useing it so you can debug the load process.

    But really, you need to untaint $RealBin. Something like:

    BEGIN { use FindBin qw($RealBin); my ($cleanPath) = $RealBin =~ m/(some sane path match here)/; use lib $FindBin::Bin; }
    Optimising for fewest key strokes only makes sense transmitting to Pluto or beyond
      Is there some reason you can't run the code under the debugger or, even better, use an IDE such as Komodo?

      I can't use an IDE as this is running on shared hosting.

      Having never used the Perl debugger, I would not know where to start or how to use the information it gave me. Perhaps I should look at it.

        "I can't use an IDE as this is running on shared hosting."

        Of course you can use an IDE. There are several ways you can go about it depending on the IDE, but at least you can copy the code to your local machine mocking up parts of the system as needed. At best your IDE can connect to a remote system and let you debug the code running on that system. Using a good IDE for debugging is vastly more productive than any other technique.

        While not as good as an IDE, the Perl debugger allows you to place breakpoints to pause execution while you inspect the state of variables. You can then trace through code one statement at a time to see where execution really goes. See perldebtut. If you do any significant amount of coding the time spent to use a debugger will be paid back in time saved many times over!

        Optimising for fewest key strokes only makes sense transmitting to Pluto or beyond
Re: Debugging a module that's failing under taint mode
by Aldebaran (Curate) on Jul 01, 2021 at 22:55 UTC
    Any suggestions for debugging where the problem might be in Site::HTML as the error doesn't tell me where in the module to look?

    Why not the debugger? Is there something inimical to using -dT simultaneously? I tried it with afoken's script from the above-sited thread and got an interesting and informative look at how Data::Dumper implemented a hash dump of the envelope. One thing I like about running scripts like this is that I don't know what's gonna happen, and I need the output to make sense of the source:

    Presumably, there is a Site.pm file on your system. Use the line

    f HTML.pm

    , and the debugger will start there. You're not limited to "walking." Try the M or y command and see how perl views your software.

    Good Luck,

      The OPs problem happened at compile time.

      The debugger called with perl -dT would have only kicked in after the problem already happened.

      If you wanted to show how to use the debugger you should have probably

      • reproduced his problem first
      • shown how to set a breakpoint early at compile-time.

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery