คำเตือน: การเรียกใช้คำสั่งนี้ในเชลล์ส่วนใหญ่จะส่งผลให้ระบบแตกหักซึ่งจะต้องบังคับให้ปิดระบบเพื่อแก้ไข
ฉันเข้าใจฟังก์ชั่นวนซ้ำ:(){ :|: & };:และสิ่งที่ทำ แต่ฉันไม่รู้ว่าระบบสายส้อมอยู่ที่ไหน ผมไม่แน่ใจ |แต่ผมสงสัยว่าในท่อ
คำเตือน: การเรียกใช้คำสั่งนี้ในเชลล์ส่วนใหญ่จะส่งผลให้ระบบแตกหักซึ่งจะต้องบังคับให้ปิดระบบเพื่อแก้ไข
ฉันเข้าใจฟังก์ชั่นวนซ้ำ:(){ :|: & };:และสิ่งที่ทำ แต่ฉันไม่รู้ว่าระบบสายส้อมอยู่ที่ไหน ผมไม่แน่ใจ |แต่ผมสงสัยว่าในท่อ
คำตอบ:
เป็นผลมาจากไปป์ในx | y, subshell ถูกสร้างขึ้นเพื่อให้มีไปป์ไลน์เป็นส่วนหนึ่งของกลุ่มกระบวนการเบื้องหน้า สิ่งนี้ยังคงสร้าง subshells (ผ่านfork()) ไปเรื่อย ๆ ดังนั้นจึงสร้าง fork bomb
$ for (( i=0; i<3; i++ )); do
> echo "$BASHPID"
> done
16907
16907
16907
$ for (( i=0; i<3; i++ )); do
> echo "$BASHPID" | cat
> done
17195
17197
17199
ทางแยกไม่ได้เกิดขึ้นจริงจนกว่าจะมีการเรียกใช้รหัสอย่างไรก็ตามซึ่งเป็นการร้องขอขั้นสุดท้าย:ในรหัสของคุณ
หากต้องการแยกการทำงานของ fork bomb:
:() - กำหนดฟังก์ชั่นใหม่ที่เรียกว่า :{ :|: & } - คำจำกัดความของฟังก์ชั่นที่ทำหน้าที่เรียกไปยังอินสแตนซ์อื่นของฟังก์ชันการโทรในพื้นหลัง: - เรียกใช้ฟังก์ชัน fork bombสิ่งนี้มีแนวโน้มที่จะไม่ได้ใช้หน่วยความจำมากเกินไป แต่มันจะดูดค่า PID และใช้รอบของ CPU
x | yทำไมมีย่อยเปลือกสร้าง? เพื่อความเข้าใจของฉันเมื่อทุบตีเห็นpipeจะรันระบบโทรที่ผลตอบแทนที่สองpipe() fdsตอนนี้ command_left เป็นexeced และเอาต์พุตถูกป้อนไปที่ command_right เป็นอินพุต ตอนนี้ command_right เป็นexeced ดังนั้นBASHPIDแต่ละครั้งแตกต่างกันอย่างไร
xและyมี 2 คำสั่งแยกกันทำงานใน 2 กระบวนการแยกกันดังนั้นคุณมี 2 subshells แยก หากxทำงานในกระบวนการเดียวกับเชลล์นั่นหมายความว่าxจะต้องเป็นบิวด์อิน
บิตสุดท้ายของรหัสกำลังเรียกใช้ฟังก์ชั่น;: :(){ ... }นี่คือที่เกิดขึ้นของส้อม
:อัฒภาคยุติคำสั่งแรกและเราจะเริ่มต้นอีกคนหนึ่งคือการเรียกใช้ฟังก์ชั่น ความหมายของฟังก์ชั่นนี้รวมถึงการเรียกร้องให้ตัวเอง ( :) :และผลผลิตของสายนี้จะประปาเป็นรุ่น กระบวนการนี้ประกอบไปด้วยกระบวนการอย่างไม่มีกำหนด
ทุกครั้งที่คุณโทรฟังก์ชั่นที่คุณกำลังเรียกใช้ฟังก์ชันซี:() fork()ในที่สุดสิ่งนี้จะทำให้หมดกระบวนการ ID (PID) ทั้งหมดในระบบ
คุณสามารถสลับ|:&กับสิ่งอื่นเพื่อที่คุณจะได้ทราบว่าเกิดอะไรขึ้น
ในหน้าต่างเทอร์มินัลหนึ่งทำได้:
$ watch "ps -eaf|grep \"[s]leep 61\""
ในหน้าต่างอื่นเราจะเรียกใช้ fork bomb รุ่นดัดแปลงเล็กน้อย รุ่นนี้จะพยายามเค้นตัวเองเพื่อให้เราสามารถศึกษาสิ่งที่กำลังทำอยู่ รุ่นของเราจะนอนหลับ 61 :()วินาทีก่อนที่จะเรียกฟังก์ชั่น
นอกจากนี้เราจะเรียกการโทรเริ่มต้นด้วยหลังจากที่มีการเรียกใช้ Ctrl+ ชนิดแล้วzbg
$ :(){ sleep 61; : | : & };:
# control + z
[1]+ Stopped sleep 61
[2] 5845
$ bg
[1]+ sleep 61 &
ตอนนี้ถ้าเรารันjobsคำสั่งในหน้าต่างเริ่มต้นเราจะเห็นสิ่งนี้:
$ jobs
[1]- Running sleep 61 &
[2]+ Running : | : &
หลังจากสองสามนาที:
$ jobs
[1]- Done sleep 61
[2]+ Done : | :
ในหน้าต่างอื่นที่เราใช้งานอยู่watch:
Every 2.0s: ps -eaf|grep "[s]leep 61" Sat Aug 31 12:48:14 2013
saml 6112 6108 0 12:47 pts/2 00:00:00 sleep 61
saml 6115 6110 0 12:47 pts/2 00:00:00 sleep 61
saml 6116 6111 0 12:47 pts/2 00:00:00 sleep 61
saml 6117 6109 0 12:47 pts/2 00:00:00 sleep 61
saml 6119 6114 0 12:47 pts/2 00:00:00 sleep 61
saml 6120 6113 0 12:47 pts/2 00:00:00 sleep 61
saml 6122 6118 0 12:47 pts/2 00:00:00 sleep 61
saml 6123 6121 0 12:47 pts/2 00:00:00 sleep 61
และps -auxfแสดงลำดับชั้นของกระบวนการนี้:
$ ps -auxf
saml 6245 0.0 0.0 115184 5316 pts/2 S 12:48 0:00 bash
saml 6247 0.0 0.0 100988 468 pts/2 S 12:48 0:00 \_ sleep 61
....
....
saml 6250 0.0 0.0 115184 5328 pts/2 S 12:48 0:00 bash
saml 6268 0.0 0.0 100988 468 pts/2 S 12:48 0:00 \_ sleep 61
saml 6251 0.0 0.0 115184 5320 pts/2 S 12:48 0:00 bash
saml 6272 0.0 0.0 100988 468 pts/2 S 12:48 0:00 \_ sleep 61
saml 6252 0.0 0.0 115184 5324 pts/2 S 12:48 0:00 bash
saml 6269 0.0 0.0 100988 464 pts/2 S 12:48 0:00 \_ sleep 61
...
...
killall bashจะหยุดสิ่งก่อนที่พวกเขาได้รับจากมือ การทำความสะอาดของคุณด้วยวิธีนี้อาจเป็นมือที่หนักหนากว่าซึ่งเป็นวิธีที่อ่อนโยนกว่าซึ่งจะไม่ทำลายbashเปลือกหอยลงทุกครั้ง
กำหนดเทอร์มินัลเทียมหลอกว่า fork bomb กำลังจะทำงาน
$ tty
/dev/pts/4
ฆ่าสถานีหลอก
$ pkill -t pts/4แต่ละการเรียกใช้ของbashและsleepเป็นการเรียกใช้ฟังก์ชัน C fork()จากbashเชลล์จากตำแหน่งที่คำสั่งรัน
bashอาจกำลังรันอยู่บนเทอร์มินัลแยกกัน pkill -t pts/2ดีกว่าที่จะใช้