Tại sao tôi không thể đánh sập hệ thống của mình bằng một quả bom ngã ba?


54

Gần đây tôi đã tìm hiểu thông tin về các quy trình trong GNU / Linux và tôi đã gặp quả bom ngã ba khét tiếng:

:(){ : | :& }; :

Về mặt lý thuyết, nó được cho là tự nhân đôi vô hạn cho đến khi hệ thống hết tài nguyên ...

Tuy nhiên, tôi đã thử kiểm tra cả trên bản phân phối Debian CLIGUI Mint và dường như nó không ảnh hưởng nhiều đến hệ thống. Vâng, có hàng tấn các quy trình được tạo ra và sau một thời gian tôi đọc các thông báo trong bảng điều khiển như:

bash: fork: Tài nguyên tạm thời không có

bash: fork: thử lại: Không có tiến trình con

Nhưng sau một thời gian, tất cả các quy trình chỉ bị giết và mọi thứ trở lại bình thường. Tôi đã đọc rằng ulimit đặt số lượng quá trình tối đa cho mỗi người dùng, nhưng dường như tôi không thể nâng cao nó thực sự.

Các hệ thống bảo vệ chống lại một quả bom ngã ba là gì? Tại sao nó không tự sao chép cho đến khi mọi thứ đóng băng hoặc ít nhất là chậm lại rất nhiều? Có cách nào để thực sự đánh sập một hệ thống bằng bom ngã ba không?


2
PID tối đa của bạn hiện đang được đặt là gì?
dsstorefile1

5
Lưu ý rằng bạn sẽ không gặp sự cố khi hệ thống của bạn sử dụng bom ngã ba ... như bạn đã nói, bạn sẽ cạn kiệt tài nguyên và không thể sinh ra các quy trình mới nhưng hệ thống không nên gặp sự cố
Josh

2
Điều gì xảy ra nếu bạn chạy :(){ :& :; }; :thay thế? Có phải cuối cùng họ cũng bị giết? Thế còn :(){ while :& do :& done; }; :?
mtraceur

Câu hỏi tuyệt vời này của bạn đã thuyết phục tôi suy nghĩ lại về việc bỏ phiếu "bỏ kín" trước đây của tôi. Tuy nhiên, "Tôi" luôn viết hoa bằng tiếng Anh, xin vui lòng đừng viết nó quá tệ nữa.
user259412

Câu trả lời:


85

Bạn có thể có một bản phân phối Linux sử dụng systemd.

Systemd tạo một nhóm cho mỗi người dùng và tất cả các quy trình của người dùng thuộc về cùng một nhóm.

Cgroups là một cơ chế Linux để đặt giới hạn cho tài nguyên hệ thống như số lượng quá trình tối đa, chu kỳ CPU, mức sử dụng RAM, v.v ... Đây là một lớp giới hạn tài nguyên khác, hiện đại hơn so với ulimit(sử dụng tòa nhà getrlimit()).

Nếu bạn chạy systemctl status user-<uid>.slice(đại diện cho nhóm của người dùng), bạn có thể thấy số lượng tác vụ hiện tại và tối đa (quy trình và luồng) được phép trong nhóm đó.

$ systemctl status user- $ UID.slice
● user-22001.slice - Lát người dùng của UID 22001
   Đã tải: đã tải
  Thả vào: /usr/lib/systemd/system/user-.slice.d
           └─10-mặc định.
   Hoạt động: hoạt động kể từ Thứ Hai 2018-09-10 17:36:35 EEST; 1 tuần 3 ngày trước
    Nhiệm vụ: 17 (giới hạn: 10267)
   Bộ nhớ: 616,7M

Theo mặc định, số lượng tác vụ tối đa mà systemd sẽ cho phép cho mỗi người dùng là 33% "tối đa toàn hệ thống" ( sysctl kernel.threads-max); điều này thường lên tới ~ 10.000 nhiệm vụ. Nếu bạn muốn thay đổi giới hạn này:

  • Trong systemd v239 trở lên, mặc định của người dùng được đặt thông qua T taskMax = in:

    /usr/lib/systemd/system/user-.slice.d/10-defaults.conf
    

    Để điều chỉnh giới hạn cho một người dùng cụ thể (sẽ được áp dụng ngay lập tức cũng như được lưu trữ trong /etc/systemd/system.control), hãy chạy:

    systemctl [--runtime] set-property user-<uid>.slice TasksMax=<value>
    

    Các cơ chế thông thường để ghi đè cài đặt của một đơn vị (chẳng hạn như systemctl edit) cũng có thể được sử dụng ở đây, nhưng chúng sẽ yêu cầu khởi động lại. Ví dụ: nếu bạn muốn thay đổi giới hạn cho mọi người dùng, bạn có thể tạo /etc/systemd/system/user-.slice.d/15-limits.conf.

  • Trong systemd v238 trở về trước, mặc định của người dùng được đặt thông qua UserT taskMax = in /etc/systemd/logind.conf. Thay đổi giá trị thường yêu cầu khởi động lại.

Thông tin thêm về điều này:


5
Và 12288 quy trình (trừ những gì đã sinh ra trước khi đánh bom) không làm gì ngoài việc cố gắng tạo ra một quy trình mới, không thực sự ảnh hưởng đến một hệ thống hiện đại.
Cột

13

Điều này sẽ không sụp đổ các hệ thống Linux hiện đại nữa.

Nó tạo ra rất nhiều tiến trình nhưng không thực sự đốt cháy hết CPU khi các tiến trình không hoạt động. Bạn hết chỗ trong bảng quy trình trước khi hết RAM ngay bây giờ.

Nếu bạn không bị giới hạn nhóm như Hkoof chỉ ra, sự thay đổi sau đây vẫn khiến các hệ thống ngừng hoạt động:

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

5
Điều này thực sự phụ thuộc vào những gì bạn cho là 'sự cố' hệ thống. Hầu hết các vị trí trong bảng quy trình sẽ khiến một hệ thống phải quỳ xuống trong hầu hết các trường hợp, ngay cả khi nó không hoàn toàn gây ra sự hoảng loạn hạt nhân.
Austin Hemmelgarn

4
@AustinHemmelgarn: Đó là lý do tại sao các hệ thống khôn ngoan dành 4 id quá trình cuối cùng cho root.
Joshua

2
Tại sao các quá trình sẽ "nhàn rỗi"? Mỗi quá trình rẽ nhánh là trong một đệ quy vô hạn của việc tạo ra nhiều quá trình. Vì vậy, nó dành rất nhiều thời gian cho chi phí cuộc gọi hệ thống ( forklặp đi lặp lại) và phần còn lại của thời gian thực hiện cuộc gọi chức năng (có thể sử dụng nhiều bộ nhớ hơn cho mỗi cuộc gọi trong ngăn xếp cuộc gọi của shell).
mtraceur

4
@mtraceur: Nó chỉ xảy ra khi forking bắt đầu thất bại.
Joshua

1
Ồ, tôi lấy lại. Tôi đã mô hình hóa logic của việc triển khai bom ngã ba hơi khác trong đầu (như thế này :(){ :& :; }; ::) thay vì câu hỏi trong câu hỏi. Tôi thực sự chưa nghĩ hết về dòng chảy thực thi của nguyên mẫu như đã cho.
mtraceur

9

Trở lại những năm 90, tôi vô tình giải phóng một trong những thứ này cho chính mình. Tôi đã vô tình thiết lập bit thực thi trên tệp nguồn C có lệnh fork () trong đó. Khi tôi nhấp đúp vào nó, csh đã cố chạy nó thay vì mở nó trong một trình soạn thảo như tôi muốn.

Ngay cả sau đó, nó đã không sụp đổ hệ thống. Unix đủ mạnh để tài khoản của bạn và / hoặc HĐH sẽ có giới hạn quy trình. Điều xảy ra thay vào đó là nó trở nên siêu chậm chạp, và bất cứ điều gì cần để bắt đầu một quá trình có thể sẽ thất bại.

Điều xảy ra đằng sau hậu trường là bảng quy trình lấp đầy các quy trình đang cố gắng tạo các quy trình mới. Nếu một trong số chúng chấm dứt (do lỗi trên ngã ba vì bảng quy trình đã đầy hoặc do người vận hành tuyệt vọng cố gắng khôi phục sự tỉnh táo cho hệ thống của họ), một trong các quy trình khác sẽ nhanh chóng rẽ nhánh một cái mới để lấp đầy khoảng trống.

"Bom ngã ba" về cơ bản là một hệ thống tự sửa chữa vô tình các quy trình trong một nhiệm vụ để giữ cho bảng quy trình của bạn đầy đủ. Cách duy nhất để ngăn chặn nó là bằng cách nào đó giết tất cả chúng cùng một lúc.


1
Giết tất cả chúng cùng một lúc dễ dàng hơn bạn nghĩ - SIGSTOP tất cả chúng trước tiên.
Điểm_Under

2
@Score_Under - Tôi hy vọng bạn sẽ tha thứ cho tôi nếu tôi không ngay lập tức chạy đến Harris Nighthawk gần nhất để xem điều đó có khắc phục được sự cố ở đó không. Tôi nghĩ rằng chỉ cần nhận được một tín hiệu PID gửi tín hiệu trước khi nó chết vì ngã ba thất bại và việc khác diễn ra có thể là một thách thức, nhưng tôi phải thử.
TED

@TED ​​kill -9 -1 có thể là bạn của bạn ở đây (với cùng một người dùng chạy bom ngã ba; không phải root).
Andreas Krey

@AndreasKrey - Lá cờ đó trông không quen, vì vậy tôi nghi ngờ Nighthawk thời 90 của tôi đã có nó.
TED

1
@TED: -1không phải là cờ. killchỉ mất một tùy chọn sau đó dừng phân tích tùy chọn. Điều này giết chết id quá trình -1, là bí danh cho tất cả các quy trình.
Joshua
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.