ปัญหาคือในกรณีที่เนื้อหาของ$xไม่ได้ถูกสุขอนามัยและมีข้อมูลที่อาจอยู่ภายใต้การควบคุมของผู้โจมตีในกรณีที่รหัสเชลล์อาจถูกใช้ในบริบทการยกระดับสิทธิ์ (เช่นสคริปต์ที่เรียกโดย setuid แอปพลิเคชันสคริปต์ sudoers หรือใช้เพื่อประมวลผลข้อมูลนอกเครือข่าย (CGI, DHCP hook ... ) โดยตรงหรือโดยอ้อม)
ถ้า:
x='(PATH=2)'
แล้ว:
x=$((1-$x)))
มีผลข้างเคียงของการตั้งค่าPATHเป็น2(เส้นทางสัมพัทธ์ที่อาจอยู่ภายใต้การควบคุมของผู้โจมตีได้เป็นอย่างดี) คุณสามารถแทนที่PATHด้วยLD_LIBRARY_PATHหรือIFS... สิ่งเดียวกันนี้เกิดขึ้นกับx=$((1-x))ใน bash, zsh หรือ ksh (ไม่ใช่เส้นประหรือ yash ที่ยอมรับค่าคงที่ตัวเลขในตัวแปรที่มีเท่านั้น)
โปรดทราบว่า:
x=$((1-$x))
จะไม่ทำงานอย่างถูกต้องสำหรับค่าลบของ$xในเชลล์บางตัวที่ใช้ตัวดำเนินการ (เป็นทางเลือกตาม POSIX) --(ลดลง) (เช่นเดียวกับx=-1ที่หมายถึงการขอให้เชลล์ประเมิน1--1ค่านิพจน์ทางคณิตศาสตร์) "$((1-x))"ไม่ได้มีปัญหาตามที่ได้xรับการขยายเป็นส่วนหนึ่งของการประเมินเลขคณิต (ไม่ใช่ก่อนหน้านี้)
ในbash, zshและksh(ไม่ใช่dashหรือyash) ถ้าxเป็น:
x='a[0$(uname>&2)]'
จากนั้นการขยาย$((1-$x))หรือ$((1-x))ทำให้unameคำสั่งนั้นถูกเรียกใช้งาน (สำหรับzsh, aจะต้องเป็นตัวแปรอาร์เรย์ แต่สามารถใช้psvarเพื่ออินสแตนซ์สำหรับสิ่งนั้นได้)
สรุปหนึ่งไม่ควรใช้ uninitialised หรือไม่ปรุงแต่งข้อมูลภายนอกในการแสดงออกทางคณิตศาสตร์ในเปลือกหอย (หมายเหตุว่าการประเมินทางคณิตศาสตร์สามารถทำได้โดย$((...))(หรือที่รู้จัก$[...]ในbashหรือzsh) แต่ยังขึ้นอยู่กับเปลือกในที่let, [/ test, declare/typeset/export..., return, break, continue, exit, printf, printบิวด์อิน, ดัชนีอาเรย์((..))และ[[...]]โครงสร้างเพื่อตั้งชื่อไม่กี่)
ในการตรวจสอบว่าตัวแปรมีตัวเลขจำนวนเต็มฐานสิบที่แท้จริงคุณสามารถใช้ POSIXly:
case $var in
("" | - | *[!0123456789-]* | ?*-*) echo >&2 not a valid number; exit 1;;
esac
ระวังว่า[0-9]ในบางพื้นที่ตรงกับมากกว่า 0123456789 [[:digit:]]ควรจะตกลง แต่ฉันจะไม่เดิมพัน
โปรดจำไว้ว่าตัวเลขที่มีเลขศูนย์นำหน้าจะถือว่าเป็นเลขฐานแปดในบางบริบท ( 010บางครั้งคือ 10, บางครั้ง 8) และระวังว่าการตรวจสอบข้างต้นจะให้ตัวเลขที่อาจใหญ่กว่าจำนวนเต็มสูงสุดที่ระบบของคุณสนับสนุน ใช้จำนวนเต็มนั้นใน; bash เช่นถือว่า 18446744073709551616 เป็น 0 เท่ากับ 2 64 ) ดังนั้นคุณอาจต้องการเพิ่มการตรวจสอบพิเศษในคำสั่งกรณีข้างต้นเช่น:
(0?* | -0?*)
echo >&2 'Only decimal numbers without leading 0 accepted'; exit 1;;
(-??????????* | [!-]?????????*)
echo >&2 'Only numbers from -999999999 to 999999999 supported'; exit 1;;
ตัวอย่าง:
$ export 'x=psvar[0$(uname>&2)]'
$ ksh93 -c 'echo "$((x))"'
Linux
ksh93: psvar: parameter not set
$ ksh93 -c '[ x -lt 2 ]'
Linux
ksh93: [: psvar: parameter not set
$ bash -c 'echo "$((x))"'
Linux
0
$ bash -c '[[ $x -lt 2 ]]'
Linux
$ bash -c 'typeset -i a; export a="$x"'
Linux
$ bash -c 'typeset -a a=([x]=1)'
Linux
$ bash -c '[ -v "$x" ]'
Linux
$ mksh -c '[[ $x -lt 2 ]]'
Linux
$ zsh -c 'echo "$((x))"'
Linux
0
$ zsh -c 'printf %d $x'
Linux
0
$ zsh -c 'integer x'
Linux
$ zsh -c 'exit $x'
Linux
อ่านเพิ่มเติมได้ที่:
x='P=3'; : $(($x + 5))จะตั้งP8 แต่x='P=3'; : $((x + 5))จะตั้งPไป3(ในzsh,kshหรือbash) "สิ่งเดียวกันนี้เกิดขึ้นกับ$((x + 1))... " ไม่ถูกต้องในขณะนี้ มันจะตั้งPATHเพื่อ2เป็นของเดิม