2

I have a function like this:

open my $pipe, "-|", '/usr/bin/externalcmd | /usr/bin/awk \'{print $2" "$4}\''
    || die "can't fork command: $!";    

while (<$pipe>) { 
    my ($if, $ip) = split;

    my $file = "/some/file/$if";
    open (FILE, ">$file") || die "can't open $file for $ip: $!";
    
    # ...

    close(FILE);
}    
close ($pipe);

It fails on open with the following error:

Insecure dependency in open while running with -T switch at line 1383, <$pipe> line 1.

How can I fix this?

Lucky
  • 627
  • 5
  • 15
  • 1
    Your program is using the `-T` switch, probably on the shebang line at the top. E.g. `#!/usr/bin/perl -Tw`. It is meant to provide safety to a program by forcing you to detaint data coming from outside sources. – TLP Aug 08 '22 at 22:23
  • 1
    More specifically, the line read from `$pipe`, split into `$if` and used in an `open` statement, which is using the infamously insecure two argument open. Two argument open in Perl is a common way to introduce code injection attacks. – TLP Aug 08 '22 at 22:25
  • 2
    See https://perldoc.perl.org/perlsec#Taint-mode – Shawn Aug 08 '22 at 22:25
  • 1
    The link posted by @Shawn has it all but I'd raise another question. The code opens a process which runs a cmd which is piped to `awk` for processing and only then piped into the program ... why that awk? Just pipe the `externalcmd` into your Perl program and off you go. Much less complexity and far superior processing power. (Not that anything at all is wrong with `awk` but you are piping data into Perl and doing something with it anyway, so might as well remove one step in the process.) – zdim Aug 08 '22 at 23:46
  • I understand what you are saying. To me, it has a semantic distinction: *this* script depends on columns x & y of *externalcmd*. All else being equal, I'd rather do as you say. – Lucky Aug 08 '22 at 23:56
  • "_has a semantic distinction_" -- ah, OK :) If you've got a point that's different, and it is a good one I think. (But it is paid for by extra two layers of complexity: the `awk` processing and the necessity of bringing in a shell, to pipe data into `awk`.) – zdim Aug 09 '22 at 00:18

1 Answers1

1

The answer was to "launder" the $if variable through a regex match like this:

# e.g., only "word" characters
if ($if =~ /^([-\@\w.]+)\z/) {
    $if = $1;
} else {
    die "Bad data in '$if'";
}

Then proceed as before.

ikegami
  • 367,544
  • 15
  • 269
  • 518
Lucky
  • 627
  • 5
  • 15
  • 2
    That's it? I'd still strongly recommend to use the three-argument `open`. Also, add the final tests: `close or ...;` – zdim Aug 09 '22 at 00:21
  • Interesting -- does the taintedness check actually need the whole if-else? (Does it not pass with the equivalent `die "..." if not $if =~ /.../;` ?) – zdim Aug 09 '22 at 00:28
  • @zdim that doesn't untaint – ikegami Aug 09 '22 at 02:35
  • But `($if) = $if =~ /.../ or die` would work – ikegami Aug 09 '22 at 02:36
  • @ikegami OK, so it doesn't ... thank you ... that was my question (I've no idea how it is decided -- it's some level/sort of static analysis I guess) – zdim Aug 09 '22 at 03:53
  • 1
    @zdim, Re "*I've no idea how it is decided*", well, the statement you used doesn't modify `$if` at all, so it definitely doesn't remove taint. But captures don't inherit taint, so those can be used to remove taint. – ikegami Aug 09 '22 at 04:14
  • @zdim re: three-argument open; certainly. – Lucky Aug 09 '22 at 14:23