Qual è il problema
Innanzitutto, come per molte utility, avrai un problema con i nomi dei file che iniziano con -
. Nel frattempo:
sh -c 'inline sh script here' other args
Gli altri argomenti vengono passati a inline sh script
; con l' perl
equivalente,
perl -e 'inline perl script here' other args
Gli altri argomenti vengono analizzati per più opzioni per perl prima, non lo script inline. Ad esempio, se esiste un file chiamato -eBEGIN{do something evil}
nella directory corrente,
perl -ne 'inline perl script here;' *
(con o senza -n
) farà qualcosa di malvagio.
Come per altre utility, la soluzione è quella di utilizzare il marker di fine opzioni ( --
):
perl -ne 'inline perl script here;' -- *
Ma anche in questo caso, è ancora pericoloso e dipende <>
dall'operatore utilizzato da -n
/ -p
.
Il problema è spiegato nella perldoc perlop
documentazione.
Tale operatore speciale viene utilizzato per leggere una riga (un record, i record sono righe per impostazione predefinita) dell'input, in cui l'input proviene da ciascuno degli argomenti a sua volta passati @ARGV
.
Nel:
perl -pe '' a b
-p
implica un while (<>)
ciclo attorno al codice (qui vuoto).
<>
si aprirà prima a
, leggerà i record una riga alla volta fino a quando il file non sarà esaurito e quindi si aprirà b
...
Il problema è che, per aprire il file, utilizza la prima forma non sicura di open
:
open ARGV, "the file as provided"
Con quel modulo, se l'argomento è
"> afile"
, si apre afile
in modalità di scrittura,
"cmd|"
, viene eseguito cmd
e legge l'output.
"|cmd"
, hai uno stream aperto per la scrittura nell'input di cmd
.
Quindi per esempio:
perl -pe '' 'uname|'
Non genera il contenuto del file chiamato uname|
(un nome file perfettamente valido tra l'altro), ma l'output del uname
comando.
Se stai correndo:
perl -ne 'something' -- *
E qualcuno ha creato un file chiamato rm -rf "$HOME"|
(di nuovo un nome file perfettamente valido) nella directory corrente (ad esempio perché quella directory una volta era scrivibile da altri, o hai estratto un archivio dannoso, o hai eseguito un comando dodgy, o un'altra vulnerabilità in alcuni altri software è stata sfruttata), quindi sei in grossi guai. Aree in cui è importante essere consapevoli di questo problema sono gli strumenti che elaborano automaticamente i file in aree pubbliche come /tmp
(o strumenti che possono essere chiamati da tali strumenti).
File chiamati > foo
, foo|
, |foo
sono un problema. Ma in misura minore < foo
e foo
con caratteri di spaziatura ASCII iniziali o finali (inclusi spazio, tabulazione, nuova riga, cr ...), ciò significa che i file non verranno elaborati o che quello sbagliato sarà.
Attenzione anche che alcuni caratteri in alcuni set di caratteri multi-byte (come ǖ
in BIG5-HKSCS) finiscono nel byte 0x7c, la codifica di |
.
$ printf ǖ | iconv -t BIG5-HKSCS | od -tx1 -tc
0000000 88 7c
210 |
0000002
Quindi nei locali che usano quel set di caratteri,
perl -pe '' ./nǖ
Avrebbe cercato di eseguire il ./n\x88
comando come perl
sarebbe non cercare di interpretare che il nome del file in locale dell'utente!
Come risolvere / aggirare
AFAIK, non c'è nulla che tu possa fare per modificare quel comportamento predefinito non sicuro di perl
una volta per tutte a livello di sistema.
Innanzitutto, il problema si verifica solo con i caratteri all'inizio e alla fine del nome del file. Quindi, mentre perl -ne '' *
o perl -ne '' *.txt
sono un problema,
perl -ne 'some code' ./*.txt
non è perché tutti gli argomenti ora iniziano con ./
e fine a se .txt
(quindi non -
, <
, >
, |
, spazio ...). Più in generale, è una buona idea per il prefisso gocce con ./
. Ciò evita anche problemi con i file chiamati -
o che iniziano con -
molte altre utilità (e qui, ciò significa che non è più necessario l'indicatore end-of-options ( --
)).
L'uso -T
per attivare la taint
modalità aiuta in una certa misura. Annullerà il comando se viene rilevato tale file dannoso (solo per i casi >
e |
, non comunque <
o gli spazi bianchi).
È utile quando si utilizzano tali comandi in modo interattivo in quanto ti avverte che sta succedendo qualcosa di complicato. Tuttavia, ciò potrebbe non essere desiderabile quando si esegue l'elaborazione automatica, poiché ciò significa che qualcuno può far fallire l' elaborazione semplicemente creando un file.
Se vuoi elaborare tutti i file, indipendentemente dal loro nome, puoi usare il ARGV::readonly
perl
modulo su CPAN (sfortunatamente di solito non installato di default). Questo è un modulo molto breve che fa:
sub import{
# Tom Christiansen in Message-ID: <24692.1217339882@chthon>
# reccomends essentially the following:
for (@ARGV){
s/^(\s+)/.\/$1/; # leading whitespace preserved
s/^/< /; # force open for input
$_.=qq/\0/; # trailing whitespace preserved & pipes forbidden
};
};
Fondamentalmente, sanifica @ARGV trasformandolo " foo|"
ad esempio in "< ./ foo|\0"
.
Puoi fare lo stesso in BEGIN
un'istruzione nel tuo perl -n/-p
comando:
perl -pe 'BEGIN{$_.="\0" for @ARGV} your code here' ./*
Qui lo semplificiamo partendo dal presupposto che ./
viene utilizzato.
Un effetto collaterale di che (e ARGV::readonly
) è però che $ARGV
in your code here
mostra che trascinamento carattere NUL.
Aggiornamento 03/06/2015
perl
v5.21.5 e soprattutto avere un nuovo <<>>
operatore che si comporta come <>
se non che essa non farlo lavorazioni speciali. Gli argomenti verranno considerati solo come nomi di file. Quindi con quelle versioni, ora puoi scrivere:
perl -e 'while(<<>>){ ...;}' -- *
(non dimenticare --
o utilizzare ./*
però) senza timore di sovrascrivere i file o eseguire comandi imprevisti.
-n
/ -p
uso comunque la <>
forma pericolosa . E attenzione, i collegamenti simbolici sono ancora seguiti, quindi ciò non significa necessariamente che sia sicuro da usare in directory non attendibili.