Opciones de línea de comando ambiguas de Perl e implicaciones de seguridad de eval con -i?

Sé que esto es incorrecto. Solo quiero saber cómo perl analiza esto.

Entonces, estoy jugando con Perl, lo que quería era perl -ne lo que tecleé fue perl -ie el comportamiento fue bastante interesante, y me gustaría saber qué sucedió.

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

Así que perla Aborted (core dumped) en ese. Leer perl --help Ya veo -i toma una extensión para copias de seguridad.

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

Para los que no saben -e es solo evaluación. Así que estoy pensando que una de las tres cosas podría haber sucedido, ya sea que se analizara como

  1. perl -i -e'next unless /g/i' me sale undef, el resto va como argumento a e
  2. perl -ie 'next unless /g/i' obtengo el argumento e, el resto cuelga como un nombre de archivo
  3. perl -i"-e'next unless /g/i'" todo como un argumento para mí

Cuando corro

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

El programa no aborta. Esto me lleva a creer que 'next unless /g/i' no se está analizando como un argumento literal para -e. Sin ambigüedades, lo anterior se analizaría de esa manera y tiene un resultado diferente.

¿Así que qué es lo? Bueno, jugando un poco más, tengo

$ echo 1 | perl -ie'foo bar'
Unrecognized switch: -bar  (-h will show valid options).

$ echo 1 | perl -ie'foo w w w'
... works fine guess it reads it as `perl -ie'foo' -w -w -w`

Jugando con lo anterior, intento esto...

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

Ahora estoy realmente confundido... Entonces, ¿cómo analiza Perl esto? Por último, parece que en realidad puede obtener un comando de evaluación de Perl desde solo -i. ¿Tiene esto implicaciones de seguridad?

$ perl -i'foo e eval "warn q[bar]" '

preguntado el 22 de mayo de 12 a las 20:05

Parece que Perl se está tragando todo lo que sigue a la -i cambiar como su argumento. -

@JRFerguson no para mí, parece que Perl simplemente asume -i toma todos los caracteres hasta el primer espacio en blanco, y luego parece que ejecuta su propia forma de análisis de línea de comando en el resto de la entrada. -

De hecho, eso es lo que estoy diciendo. -

por cierto, no hay implicaciones de seguridad. perl -e'...' no puedes hacer nada que no puedas hacer con perl somefile.pl. -

Pero, siendo capaz de establecer el argumento para perl -i no debería proporcionarle las mismas habilidades que ser capaz de establecer el argumento para perl -e or perl $file. -

2 Respuestas

Respuesta rápida

El procesamiento de cotizaciones de Shell colapsa y concatena lo que cree que es un solo argumento. Su invocación es equivalente a

$ perl '-ienext unless /g/i'

Se aborta inmediatamente porque Perl analiza este argumento como si contuviera -u, que desencadena un volcado del núcleo donde comenzaría la ejecución de su código. Esta es una función antigua que alguna vez se usó para crear pseudo-ejecutables, pero es de naturaleza vestigial en estos días.

Lo que parece ser una llamada a eval es el análisis erróneo de -e 'ss /g/i'.

primera pista

B :: Deparse puede su amigo, siempre que esté ejecutando en un sistema sin dump apoyo.

$ 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');
}

Entonces, ¿por qué unle ¿desaparecer? Si está ejecutando Linux, es posible que ni siquiera haya llegado tan lejos como yo. El resultado anterior es de Perl en Cygwin, y el error sobre dump no tener soporte es una pista.

siguiente pista

De nota de la documentación de perlrun:

-u

Este cambio hace que Perl descargue el núcleo después de compilar su programa. Luego, en teoría, puede tomar este volcado del núcleo y convertirlo en un archivo ejecutable utilizando el deshacerse programa (no suministrado). Esto acelera el inicio a expensas de algo de espacio en disco (que puede minimizar eliminando el ejecutable). (Aún así, un ejecutable "hola mundo" sale a unos 200K en mi máquina). Si desea ejecutar una parte de su programa antes de descargar, use el dump operador en su lugar. Nota: disponibilidad de deshacerse es específico de la plataforma y puede no estar disponible para un puerto específico de Perl.

Hipótesis de trabajo y confirmación

El procesamiento de argumentos de Perl ve el fragmento completo como un solo grupo de opciones porque comienza con un guión. los -i opción consume la siguiente palabra (enext), como podemos ver en la implementación para -i tratamiento.

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;

Para la extensión del archivo de copia de seguridad, el código anterior de perl.c consume hasta el primer carácter de espacio en blanco o el final de la cadena, lo que ocurra primero. Si quedan caracteres, el primero debe ser un espacio en blanco, luego omítalo, y si el siguiente es un guión, omítalo también. En Perl, puede escribir esta lógica como

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

Entonces, todos -u, -n, -ly -e son opciones válidas de Perl, por lo que el procesamiento de argumentos se las come y deja el absurdo

ss /g/i

como el argumento para -e, que perl analiza como una serie de divisiones. Pero antes de que la ejecución pueda siquiera comenzar, el arcaico -u hace que perl descargue el núcleo.

Comportamiento no deseado

Un poco aún más extraño es si pones dos espacios entre next y unless

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

el programa intenta ejecutarse. De vuelta en el ciclo principal de procesamiento de opciones vemos

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

El espacio adicional finaliza el análisis de opciones para ese argumento. Testigo:

$ perl -ie'next nonsense -garbage --foo' -e die Murió en -e línea 1.

pero sin el espacio extra que vemos

$ perl -ie'next nonsense -garbage --foo' -e die Interruptor no reconocido: -onsense -garbage --foo (-h mostrará opciones válidas).

Sin embargo, con un espacio y un guión adicionales,

$ perl -ie'next -a menos que no se admita el volcado de /g/i'.

Motivación del diseño

Como indican los comentarios, la lógica está ahí por el bien de travesura dura (#!) restricciones de línea, que Perl hace todo lo posible por solucionar.

Guiones de intérprete

Un script de intérprete es un archivo de texto que tiene habilitado el permiso de ejecución y cuya primera línea tiene el formato:

#! interpreter [optional-arg]

El intérprete debe ser un nombre de ruta válido para un ejecutable que no sea en sí mismo un script. Si el argumento de nombre de archivo de execve especifica un script de intérprete, luego se invocará al intérprete con los siguientes argumentos:

interpreter [optional-arg] filename arg...

sin que importe arg ... es la serie de palabras señaladas por el argv argumento de execve.

Para uso portátil, argumento opcional debe estar ausente o especificarse como una sola palabra (es decir,, no debe contener espacios en blanco)...

Respondido el 20 de junio de 20 a las 10:06

Si el caparazón piensa que todo es un argumento '-ienext unless /g/i' ¿Por qué Perl lo divide en espacios en blanco? ¿Por qué Perl asumiría que si asdf jkl fue enviado como un argumento, debe leerse como -asdf -jkl? ¿No debería el shell hacer el trabajo de preparar los argumentos para perl, y perl solo preocuparse por manejar los argumentos tal como están? - Evan Carroll

Desafortunadamente, usando Deparse en Mac OS X (10.6.8) con Perl 5.14.2 no es revelador en este caso. Con o sin él, uno simplemente obtiene "Abort trap". - JRFerguson

@Evan Carroll, Re "¿por qué Perl lo divide en espacios en blanco?" ¡Sospecho que tiene que ver con el manejo de opciones de Perl en el #! línea. Algunos sistemas operativos (por ejemplo, Linux) pasan todo después del comando como un único argumento. Dividir en espacios permitiría #!/usr/bin/perl -w -i trabajar. - Ikegami

@Greg Bacon, no llamaría a Linux un sistema antiguo. - Ikegami

@ikegami interesante! no sabia que el shebang fue ejecutado tan torpemente y carece de estandarización. - Evan Carroll

Tres cosas que debes saber:

  1. '-x y' significa -xy a Perl (para algunas opciones arbitrarias "x" e "y").

  2. -xy, como es común en las herramientas de Unix, es un "paquete" que representa -x -y.

  3. -i, me gusta -e absorbe el resto del argumento. a diferencia de -e, considera que un espacio es el final del argumento (según el n. ° 1 anterior).

Eso significa

-ie'next unless /g/i'

que es solo una forma elegante de escribir

'-ienext unless /g/i'

desagrega a

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

perlrun documentos -u como:

Este cambio hace que Perl descargue el núcleo después de compilar su programa. Luego, en teoría, puede tomar este volcado del núcleo y convertirlo en un archivo ejecutable utilizando el programa de undump (no suministrado). Esto acelera el inicio a expensas de algo de espacio en disco (que puede minimizar eliminando el ejecutable). (Aún así, un ejecutable "hola mundo" sale a unos 200K en mi máquina.) Si desea ejecutar una parte de su programa antes de volcarlo, use el operador dump() en su lugar. Nota: la disponibilidad de undump es específica de la plataforma y puede no estar disponible para un puerto específico de Perl.

contestado el 22 de mayo de 12 a las 22:05

Nota: no sabía el n.° 3 y me había olvidado del n.° 1, por lo que esta es una pregunta muy complicada, especialmente porque simplemente agrega -MO=Deparse no ayudó en este sistema. - Ikegami

'-x y' means -xy to Perl (for some arbitrary options "x" and "y"). ¿Es esto cierto? perl '-w edie' no funciona tal vez lo que quieres decir es que '-x y' means -xy to Perl (for some arbitrary options "x" that requires an argument, and an arbitrary argument "y")., como en el caso de perl '-e die' - Evan Carroll

@Evan Carroll, ah, ¿entonces es específico para -i? ¡impar! - Ikegami

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.