มีปัญหาอะไร
-ก่อนเช่นค่าสาธารณูปโภคจำนวนมากที่คุณจะมีปัญหากับชื่อไฟล์ที่เริ่มต้นด้วย ขณะที่อยู่ใน:
sh -c 'inline sh script here' other args
args อื่น ๆ ถูกส่งผ่านไปยังinline sh script; ด้วยความperlเสมอภาค
perl -e 'inline perl script here' other args
args อื่น ๆ จะถูกสแกนเพื่อหาตัวเลือกเพิ่มเติมเพื่อperlก่อนไม่ใช่สคริปต์แบบอินไลน์ ตัวอย่างเช่นหากมีไฟล์ที่เรียกว่า-eBEGIN{do something evil}ในไดเรกทอรีปัจจุบัน
perl -ne 'inline perl script here;' *
(มีหรือไม่มี-n) จะทำสิ่งที่ชั่วร้าย
เช่นเดียวกับยูทิลิตี้อื่น ๆ การทำงานเพื่อใช้ตัวทำเครื่องหมายจุดสิ้นสุด ( --):
perl -ne 'inline perl script here;' -- *
แต่ถึงอย่างนั้นก็ยังคงเป็นอันตรายและที่ว่าลงไปที่<>ผู้ประกอบการใช้โดย/-n-p
ปัญหาอธิบายไว้ในperldoc perlopเอกสารประกอบ
ตัวดำเนินการพิเศษนั้นจะใช้ในการอ่านหนึ่งบรรทัด (หนึ่งเรคคอร์ดบันทึกเป็นบรรทัดโดยค่าเริ่มต้น) ของอินพุตซึ่งอินพุตนั้นมาจากแต่ละอาร์กิวเมนต์ที่ส่งผ่าน@ARGVมา
ใน:
perl -pe '' a b
-pหมายถึงwhile (<>)วนรอบรหัส (ที่นี่ว่างเปล่า)
<>จะเปิดขึ้นก่อนaอ่านระเบียนทีละบรรทัดจนกว่าไฟล์จะหมดแล้วเปิดb...
ปัญหาคือการเปิดไฟล์มันใช้รูปแบบแรกที่ไม่ปลอดภัยของopen:
open ARGV, "the file as provided"
ด้วยรูปแบบนั้นถ้าอาร์กิวเมนต์เป็น
"> afile"มันจะเปิดขึ้นafileในโหมดการเขียน
"cmd|"มันทำงานcmdและอ่านผลลัพธ์
"|cmd"cmdคุณได้เปิดสตรีมสำหรับการเขียนการป้อนข้อมูลของ
ตัวอย่างเช่น:
perl -pe '' 'uname|'
ไม่ส่งออกเนื้อหาของไฟล์ที่เรียกว่าuname|(ชื่อไฟล์ที่ถูกต้องสมบูรณ์ btw) แต่เป็นเอาต์พุตของunameคำสั่ง
หากคุณกำลังทำงาน:
perl -ne 'something' -- *
และบางคนได้สร้างไฟล์ชื่อrm -rf "$HOME"|(อีกครั้งชื่อไฟล์ที่ถูกต้องสมบูรณ์) ในไดเรกทอรีปัจจุบัน (เช่นเนื่องจากไดเรกทอรีนั้นครั้งหนึ่งเคยเขียนโดยผู้อื่นหรือคุณแยกไฟล์เก็บถาวรหลบหรือคุณเรียกใช้คำสั่งหลบหรือ ช่องโหว่อื่นในซอฟต์แวร์อื่นถูกโจมตี) จากนั้นคุณประสบปัญหาใหญ่ พื้นที่ที่สิ่งสำคัญที่ต้องระวังคือเครื่องมือประมวลผลไฟล์โดยอัตโนมัติในพื้นที่สาธารณะเช่น/tmp(หรือเครื่องมือที่อาจถูกเรียกใช้โดยเครื่องมือดังกล่าว)
ไฟล์ที่เรียกว่า> foo, foo|, |fooมีปัญหา แต่ในระดับที่น้อยกว่า< fooและfooด้วยอักขระระยะห่าง ASCII ชั้นนำหรือต่อท้าย (รวมถึงช่องว่าง, แท็บ, การขึ้นบรรทัดใหม่, CR ... ) รวมถึงนั่นหมายความว่าไฟล์เหล่านั้นจะไม่ได้รับการประมวลผล
นอกจากนี้ระวังว่าอักขระบางตัวในบางชุดตัวอักษรหลายไบต์ (เช่นǖใน BIG5-HKSCS) สิ้นสุดใน 0x7c |ไบต์การเข้ารหัสของ
$ printf ǖ | iconv -t BIG5-HKSCS | od -tx1 -tc
0000000 88 7c
210 |
0000002
ดังนั้นในโลแคลที่ใช้ชุดอักขระนั้น
perl -pe '' ./nǖ
จะพยายามเรียกใช้./n\x88คำสั่งเนื่องจากperlจะไม่พยายามตีความชื่อไฟล์นั้นในภาษาของผู้ใช้!
วิธีแก้ไข / หลีกเลี่ยง
AFAIK ไม่มีอะไรที่คุณสามารถทำได้เพื่อเปลี่ยนพฤติกรรมการเริ่มต้นที่ไม่ปลอดภัยของperlครั้งเดียวและสำหรับทั้งระบบ
ครั้งแรกปัญหาเกิดขึ้นเฉพาะกับตัวอักษรที่จุดเริ่มต้นและจุดสิ้นสุดของชื่อไฟล์ ดังนั้นในขณะที่perl -ne '' *หรือperl -ne '' *.txtมีปัญหา
perl -ne 'some code' ./*.txt
ไม่ได้เพราะข้อโต้แย้งทั้งหมดนี้เริ่มต้นด้วย./และสิ้นสุดใน.txt(เพื่อไม่-, <, >, |พื้นที่ ... ) โดยทั่วไปมันเป็นความคิดที่ดีที่จะคำนำหน้าglobs./กับ นอกจากนี้ยังช่วยหลีกเลี่ยงปัญหาเกี่ยวกับไฟล์ที่เรียก-หรือเริ่มต้นด้วย-ยูทิลิตี้อื่น ๆ (และที่นี่หมายความว่าคุณไม่จำเป็นต้องทำเครื่องหมายสิ้นสุดตัวเลือก ( --) อีกต่อไป)
การใช้-Tเพื่อเปิดtaintโหมดช่วยในระดับหนึ่ง มันจะยกเลิกคำสั่งหากพบไฟล์ที่เป็นอันตรายดังกล่าว (สำหรับ>และใน|บางกรณีเท่านั้นไม่ใช่<หรือเว้นวรรค)
มีประโยชน์เมื่อใช้คำสั่งแบบโต้ตอบตามที่แจ้งเตือนคุณว่ามีบางอย่างที่เกิดขึ้น ซึ่งอาจไม่เป็นที่น่าพอใจเมื่อทำการประมวลผลอัตโนมัติเนื่องจากนั่นหมายความว่าบางคนสามารถทำให้การประมวลผลนั้นล้มเหลวเพียงแค่สร้างไฟล์
หากคุณไม่ต้องการที่จะดำเนินการทุกไฟล์โดยไม่คำนึงถึงชื่อของพวกเขาคุณสามารถใช้โมดูลใน CPAN (น่าเสียดายที่มักจะไม่ได้ติดตั้งโดยค่าเริ่มต้น) นั่นเป็นโมดูลสั้น ๆ ที่ทำ:ARGV::readonly perl
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
};
};
โดยทั่วไปจะ sanitises @ ARGV โดยการเปิดตัวอย่างลงใน" foo|""< ./ foo|\0"
คุณสามารถทำเช่นเดียวกันในBEGINคำสั่งในperl -n/-pคำสั่งของคุณ:
perl -pe 'BEGIN{$_.="\0" for @ARGV} your code here' ./*
ที่นี่เราลดความซับซ้อนของมันบนสมมติฐานที่./ใช้
ผลข้างเคียงของ (และARGV::readonly) ถึงแม้ว่า$ARGVในyour code hereนั้นแสดงให้เห็นว่าตัวละคร NUL ต่อท้าย
อัพเดท 2015-06-03
perlv5.21.5 ขึ้นไปมี<<>>โอเปอเรเตอร์ใหม่ที่ทำงานคล้ายกัน<>ยกเว้นว่ามันจะไม่ทำการประมวลผลพิเศษนั้น อาร์กิวเมนต์จะถูกพิจารณาว่าเป็นชื่อไฟล์เท่านั้น ดังนั้นด้วยเวอร์ชันเหล่านี้คุณสามารถเขียน:
perl -e 'while(<<>>){ ...;}' -- *
(อย่าลืม--หรือใช้งาน./*) โดยไม่ต้องกลัวว่าจะเขียนทับไฟล์หรือรันคำสั่งที่ไม่คาดคิด
-n/ -pยังคงใช้<>รูปแบบอันตรายแม้ว่า และระวัง symlink ยังคงมีอยู่ดังนั้นจึงไม่ได้หมายความว่าปลอดภัยที่จะใช้ในไดเรกทอรีที่ไม่น่าเชื่อถือ