Perl ambiguous command line options and eval security consequences with -i?

I know this is not true. I just want to know how perl parses this.

So, I play with perl, I wanted perl -ne what I typed was perl -ie , the behavior was interesting, and I would like to know what happened.

 $ echo 1 | perl -ie'next unless /g/i' 

So perl Aborted (core dumped) . Reading perl --help I can see that -i accepts the extension for backups.

 -i[extension] edit <> files in place (makes backup if extension supplied) 

For those who don't know -e , this is just an estimate. Therefore, I think that one of three things could happen, or it was analyzed as

  • perl -i -e'next unless /g/i' I get undef, the rest as an argument to e
  • perl -ie 'next unless /g/i' i get the argument e, the rest hangs like a file name
  • perl -i"-e'next unless /g/i'" whole thing as an argument to i

When i started

 $ echo 1 | perl -i -e'next unless /g/i' 

The program is not interrupted. This makes me think that 'next unless /g/i' not parsed as the literal argument -e . The foregoing would be explicitly analyzed in this way, and it has a different result.

So what is it? Ok, playing with a little more i got

 $ echo 1 | perl -ie'foo bar' Unrecognized switch: -bar (-h will show valid options). $ echo 1 | perl -ie'foo www' ... works fine guess it reads it as `perl -ie'foo' -w -w -w` 

Playing with the above, I try this ...

 $ echo 1 | perl -ie'foo e eval q[warn "bar"]' bar at (eval 1) line 1. 

Now I'm really confused. So how does Perl parse this? Finally, it seems that you can really get the Perl eval command from just -i . Does this have security implications?

 $ perl -i'foo e eval "warn q[bar]" ' 
+6
source share
2 answers

Quick response

Shell quotes are collapsed to combine what, in her opinion, is one argument. Your call is equivalent

 $ perl '-ienext unless /g/i' 

It is interrupted immediately because perl parses this argument as containing -u , which triggers a kernel dump when your code starts executing. This is an old function that was once used to create pseudo-executable files, but today it is rudimentary in nature.

What seems to be a call to eval is an invalid exponent -e 'ss /g/i' .

First clue

B :: Deparse can be your friend if you work on a system without dump .

 $ echo 1 | perl -MO=Deparse,-p -ie'next unless /g/i' dump is not supported. BEGIN { $^I = "enext"; } BEGIN { $/ = "\n"; $\ = "\n"; } LINE: while (defined(($_ = <ARGV>))) { chomp($_); (('ss' / 'g') / 'i'); } 

So why does unle disappear? If you start Linux again, you may not even have received, as far as I know. The above result is from Perl on Cygwin, and a dump error that is not supported is the key.

Next key

From perlrun doc :

-u

This switch causes Perl to unload the kernel after compiling your program. Then you can theoretically take this core dump and turn it into an executable file using a backup program (not supplied). This speeds up startup due to some disk space (which can be minimized by deleting the executable file). (However, the "hello world" executable is output at approximately 200K on my machine.) If you want to execute part of your program before resetting, use the dump statement instead. Note. Binding availability is platform dependent and may not be available for a specific Perl port.

Working hypothesis and confirmation

Perl & ss; processing arguments s considers the entire fragment as one cluster of parameters, since it starts with a dash. The -i option consumes the next word ( enext ), as we can see in to handle -i .

 case 'i': Safefree(PL_inplace); [Cygwin-specific code elided -geb] { const char * const start = ++s; while (*s && !isSPACE(*s)) ++s; PL_inplace = savepvn(start, s - start); } if (*s) { ++s; if (*s == '-') /* Additional switches on #! line. */ s++; } return s; 

For the file extension backup & rsquo; s the code above from perl.c consumes up to the first character of the run or the end of the line, depending on what comes first. If characters remain, the first should be a space, then skip it, and if the next is a dash, skip it as well. In Perl, you can write this logic as

 if ($$s =~ s/i(\S+)(?:\s-)//) { my $extension = $1; return $extension; } 

Then all -u , -n , -l and -e are valid Perl options, so processing the arguments eats them and leaves them meaningless

 ss /g/i 

as the -e argument, which perl parses as a series of divisions. But before execution can even begin, the archaic -u calls perl for the dump kernel.

Inadvertent behavior

Even stranger bit: if you put two spaces between next and unless

 $ perl -ie'next unless /g/i' 

the program is trying to run. Returning to the main options processing loop, we see

 case '*': case ' ': while( *s == ' ' ) ++s; if (s[0] == '-') /* Additional switches on #! line. */ return s+1; break; 

Extra space completes the parameter parsing for this argument. Witness:

  $ perl -ie'next nonsense -garbage --foo '-e die
 Died at -e line 1. 

but without extra space we see

  $ perl -ie'next nonsense -garbage --foo '-e die
 Unrecognized switch: -onsense -garbage --foo (-h will show valid options). 

With extra space and a dash, however,

  $ perl -ie'next -unless / g / i '
 dump is not supported. 

Design motivation

As you can see from the comments, logic exists for the tight restrictions of shebang ( #! ) , Which perl does its best to work.

Interpreter scripts

The interpreter script is a text file with permission permission and the first line of which looks like:

 #! interpreter [optional-arg] 

The interpreter must be a valid name for the executable, which in itself is not a script. If the filename argument in execve indicates the script interpreter, then the interpreter will be called with the following arguments:

 interpreter [optional-arg] filename arg... 

where arg ... is the series of words pointed to by argv execve .

For portable use, optional-arg must either be absent or be specified as a single word (i.e. it must not contain a space) & hellip;

+7
source

Three things to know:

  • '-x y' means -xy for Perl (for some arbitrary options "x" and "y").

  • -xy , as common to unix tools, is a "package" representing -x -y .

  • -i , like -e , absorbs the rest of the argument. Unlike -e , he believes that space should be the end of an argument (as per No. 1 above).

It means

 -ie'next unless /g/i' 

which is just a fancy way of writing

 '-ienext unless /g/i' 

divides into

 -ienext -u -n -l '-ess /g/i' ^^^^^ ^^^^^^^ ---------- ---------- val for -i val for -e 

perlrun docs -u like:

This switch causes Perl to unload the kernel after compiling your program. Then you can theoretically take this core dump and turn it into an executable file using a backup program (not supplied). This speeds up startup due to some disk space (which can be minimized by deleting the executable file). (However, the "hello world" executable is output at approximately 200K on my machine.) If you want to run part of your program before resetting, use the dump () operator instead. Note. Binding availability is platform dependent and may not be available for a specific Perl port.
+5
source

Source: https://habr.com/ru/post/916394/


All Articles