Tại sao những quả bom bash fork này hoạt động khác nhau và tầm quan trọng của & trong nó là gì?


16

Tôi hiểu cách một quả bom nĩa bình thường hoạt động, nhưng tôi thực sự không hiểu tại sao & ở phần cuối của quả bom nĩa thông thường lại được yêu cầu và tại sao các kịch bản này lại hoạt động khác nhau:

:(){ (:) | (:) }; :

:(){ : | :& }; :

Nguyên nhân gây ra sự tăng đột biến của việc sử dụng cpu trước khi đưa tôi trở lại màn hình đăng nhập. Cái sau thay vào đó chỉ khiến hệ thống của tôi đóng băng, buộc tôi phải khởi động lại mạnh mẽ. Tại sao vậy? Cả hai liên tục tạo ra các quy trình mới, vậy tại sao hệ thống lại hoạt động khác nhau?

Cả hai kịch bản cũng hành xử khác với

:(){ : | : }; :

điều này không gây ra bất kỳ vấn đề nào cả, mặc dù tôi đã mong chúng giống nhau. Trang hướng dẫn bash nói rằng các lệnh trong một đường ống đã được thực thi trong một lớp con, vì vậy tôi được tin rằng: | : nên đã đủ. Tôi tin tưởng & chỉ nên chạy đường ống trong một mạng con mới, nhưng tại sao điều đó thay đổi quá nhiều?

Chỉnh sửa: Sử dụng htop và giới hạn số lượng quy trình, tôi có thể thấy rằng biến thể đầu tiên tạo ra một cây quy trình thực tế, biến thể thứ hai tạo ra tất cả các quy trình ở cùng cấp độ và biến thể cuối cùng dường như không tạo ra bất kỳ quy trình nào ở tất cả. Điều này làm tôi bối rối hơn nữa, nhưng có lẽ nó giúp được gì đó?


2
tôi nghĩ rằng biến thể cuối cùng của bạn đang thiếu một dấu chấm phẩy::(){ : | :; }; :
adonis

Câu trả lời:


22

CẢNH BÁO KHÔNG CHẠM VÀO CHẠY NÀY TRÊN MÁY SẢN XUẤT. CHỈ KHÔNG. Cảnh báo: Để thử bất kỳ "quả bom" nào, hãy đảm bảo ulimit -uđang sử dụng. Đọc dưới đây [a] .

Chúng ta hãy xác định một hàm để có được PID và ngày (thời gian):

bize:~$ d(){ printf '%7s %07d %s\n' "$1" "$BASHPID" "$(date +'%H:%M:%S')"; }

Một bombchức năng đơn giản, không có vấn đề cho người dùng mới (tự bảo vệ mình: đọc [a] ):

bize:~$ bomb() { d START; echo "yes"; sleep 1; d END; } >&2

Khi chức năng đó được gọi để được thực thi hoạt động như sau:

bize:~$ bomb
  START 0002786 23:07:34
yes
    END 0002786 23:07:35
bize:~$

Lệnh dateđược thực thi, sau đó một chữ "có" được in, ngủ trong 1 giây, sau đó là lệnh đóng datevà cuối cùng, hàm thoát ra in một dấu nhắc lệnh mới. Không có gì lạ mắt.

| ống

Khi chúng ta gọi hàm như thế này:

bize:~$ bomb | bomb
  START 0003365 23:11:34
yes
  START 0003366 23:11:34
yes
    END 0003365 23:11:35
    END 0003366 23:11:35
bize:~$

Hai lệnh được bắt đầu tại một số thời điểm, hai kết thúc 1 giây sau đó và sau đó nhắc nhở trả về.

Đó là lý do cho đường ống |, để bắt đầu hai quá trình song song.

& lý lịch

Nếu chúng ta thay đổi cuộc gọi thêm một kết thúc &:

bize:~$ bomb | bomb &
[1] 3380
bize:~$
  START 0003379 23:14:14
yes
  START 0003380 23:14:14
yes
    END 0003379 23:14:15
    END 0003380 23:14:15

Dấu nhắc trả về ngay lập tức (tất cả các hành động được gửi đến nền) và hai lệnh được thực hiện như trước. Vui lòng lưu ý giá trị của "số công việc" [1]được in trước PID của quy trình 3380. Sau đó, cùng một số sẽ được in để chỉ ra rằng đường ống đã kết thúc:

[1]+  Done                    bomb | bomb

Đó là tác dụng của &.

Đó là lý do của &: để có được các quy trình bắt đầu nhanh hơn.

Tên đơn giản

Chúng ta có thể tạo một hàm gọi đơn giản là bđể thực thi hai lệnh. Gõ ba dòng:

bize:~$ b(){
> bomb | bomb
> }

Và thực hiện như:

bize:~$ b
  START 0003563 23:21:10
yes
  START 0003564 23:21:10
yes
    END 0003564 23:21:11
    END 0003563 23:21:11

Lưu ý rằng chúng tôi không sử dụng ;trong định nghĩa b(dòng mới được sử dụng để phân tách các yếu tố). Tuy nhiên, đối với một định nghĩa trên một dòng, thông thường sử dụng ;, như thế này:

bize:~$ b(){ bomb | bomb ; }

Hầu hết các không gian cũng không bắt buộc, chúng ta có thể viết tương đương (nhưng ít rõ ràng hơn):

bize:~$ b(){ bomb|bomb;}

Chúng ta cũng có thể sử dụng a &để tách }(và gửi hai quá trình xuống nền).

Bom.

Nếu chúng ta thực hiện chức năng cắn đuôi của nó (bằng cách gọi chính nó), chúng ta sẽ nhận được "quả bom ngã ba":

bize:~$ b(){ b|b;}       ### May look better as b(){ b | b ; } but does the same.

Và để làm cho nó gọi nhiều chức năng nhanh hơn, hãy gửi đường ống đến nền.

bize:~$ b(){ b|b&}       ### Usually written as b(){ b|b& }

Nếu chúng ta nối thêm cuộc gọi đầu tiên vào chức năng sau khi có yêu cầu ;và thay đổi tên thành :chúng ta sẽ nhận được:

bize:~$ :(){ :|:&};:

Thường được viết là :(){ :|:& }; :

Hoặc, được viết theo một cách vui vẻ, với một số tên khác (một người tuyết):

☃(){ ☃|☃&};☃

Các ulimit (mà bạn nên đặt trước khi chạy này) sẽ khiến cho dấu nhắc trở lại khá nhanh sau khi có nhiều lỗi (nhấn enter khi danh sách lỗi dừng để nhận lời nhắc).

Lý do của việc này được gọi là "bom ngã ba" là vì cách mà lớp vỏ khởi động lớp vỏ phụ là bằng cách sử dụng lớp vỏ đang chạy và sau đó gọi exec () đến quy trình rẽ nhánh bằng lệnh để chạy.

Một đường ống sẽ "rẽ nhánh" hai quá trình mới. Làm điều đó đến vô cùng gây ra một quả bom.
Hoặc một con thỏ như được gọi ban đầu vì nó sinh sản rất nhanh.


Thời gian:

  1. :(){ (:) | (:) }; time :
    Chấm dứt
    thực 0m45.627s

  2. :(){ : | :; }; time :
    Chấm dứt
    thực 0m15.283s

  3. :(){ : | :& }; time :
    thực 0m00.002 s
    Vẫn đang chạy


Ví dụ của bạn:

  1. :(){ (:) | (:) }; :

    Trong đó lần đóng thứ hai )phân tách }là phiên bản phức tạp hơn :(){ :|:;};:. Mỗi lệnh trong một ống được gọi bên trong một vỏ con. Đó là tác dụng của ().

  2. :(){ : | :& }; :

    Là phiên bản nhanh hơn, được viết không có khoảng trắng: :(){(:)|:&};:(13 ký tự).

  3. :(){ : | : }; : ### hoạt động trong zsh nhưng không phải trong bash.

    Có lỗi cú pháp (trong bash), cần có một metacharacter trước khi đóng },
    như sau:

    :(){ : | :; }; :

[a] Tạo người dùng sạch mới (Tôi sẽ gọi cho tôibize). Đăng nhập vào người dùng mới này trong bảng điều khiểnsudo -i -u bizehoặc:

$ su - bize
Password: 
bize:~$

Kiểm tra và sau đó thay đổi max user processesgiới hạn:

bize:~$ ulimit -a           ### List all limits (I show only `-u`)
max user processes              (-u) 63931
bize:~$ ulimit -u 10        ### Low
bize:~$ ulimit -a
max user processes              (-u) 1000

Chỉ sử dụng 10 hoạt động như là một người dùng mới đơn độc : bize. Nó giúp dễ dàng hơn để gọi killall -u bizevà loại bỏ hệ thống loại bỏ hầu hết (không phải tất cả) bom. Xin đừng hỏi cái nào vẫn hoạt động, tôi sẽ không nói. Nhưng vẫn: khá thấp nhưng về mặt an toàn, hãy thích ứng với hệ thống của bạn .
Điều này sẽ đảm bảo rằng "quả bom ngã ba" sẽ không làm sập hệ thống của bạn .

Đọc thêm:

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.