fork () อยู่ที่ fork fork ที่ไหน: () {: |: &};:?


25

คำเตือน: การเรียกใช้คำสั่งนี้ในเชลล์ส่วนใหญ่จะส่งผลให้ระบบแตกหักซึ่งจะต้องบังคับให้ปิดระบบเพื่อแก้ไข

ฉันเข้าใจฟังก์ชั่นวนซ้ำ:(){ :|: & };:และสิ่งที่ทำ แต่ฉันไม่รู้ว่าระบบสายส้อมอยู่ที่ไหน ผมไม่แน่ใจ |แต่ผมสงสัยว่าในท่อ


ที่เกี่ยวข้อง (และควรค่ากับการอ่าน): ส้อมระเบิดทำงานอย่างไร
terdon

คำตอบ:


30

เป็นผลมาจากไปป์ใน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แต่ละครั้งแตกต่างกันอย่างไร
Abhijeet Rastogi

2
@shadyabhi ง่ายมาก - xและyมี 2 ​​คำสั่งแยกกันทำงานใน 2 กระบวนการแยกกันดังนั้นคุณมี 2 subshells แยก หากxทำงานในกระบวนการเดียวกับเชลล์นั่นหมายความว่าxจะต้องเป็นบิวด์อิน
jw013

24

บิตสุดท้ายของรหัสกำลังเรียกใช้ฟังก์ชั่น;: :(){ ... }นี่คือที่เกิดขึ้นของส้อม

:อัฒภาคยุติคำสั่งแรกและเราจะเริ่มต้นอีกคนหนึ่งคือการเรียกใช้ฟังก์ชั่น ความหมายของฟังก์ชั่นนี้รวมถึงการเรียกร้องให้ตัวเอง ( :) :และผลผลิตของสายนี้จะประปาเป็นรุ่น กระบวนการนี้ประกอบไปด้วยกระบวนการอย่างไม่มีกำหนด

ทุกครั้งที่คุณโทรฟังก์ชั่นที่คุณกำลังเรียกใช้ฟังก์ชันซี:() 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เปลือกหอยลงทุกครั้ง

  1. กำหนดเทอร์มินัลเทียมหลอกว่า fork bomb กำลังจะทำงาน

    $ tty
    /dev/pts/4
    
  2. ฆ่าสถานีหลอก

    $ pkill -t pts/4

แล้วเกิดอะไรขึ้น

แต่ละการเรียกใช้ของbashและsleepเป็นการเรียกใช้ฟังก์ชัน C fork()จากbashเชลล์จากตำแหน่งที่คำสั่งรัน


7
bashอาจกำลังรันอยู่บนเทอร์มินัลแยกกัน pkill -t pts/2ดีกว่าที่จะใช้
Maciej Piechotka

@MaciejPiechotka - ขอบคุณสำหรับเคล็ดลับ ไม่เคยเห็นแบบนั้นมาก่อนฉันได้เพิ่มมันเข้าไปในคำตอบ!
slm
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.