2015-08-01 24 views
14

Tôi đang chạy hạt nhân 2.6.27 tùy chỉnh và tôi nhận thấy các tệp lõi được tạo trong quá trình segfault lớn hơn giới hạn kích thước tệp lõi cứng được đặt cho các quy trình.giới hạn kích thước tệp lõi có ảnh hưởng không xác định đối với các quy trình

Và điều khiến nó khó hiểu hơn là tệp lõi là chỉ đôi khi cắt ngắn (nhưng không được giới hạn bởi ulimit).

Ví dụ, đây là chương trình tôi sẽ cố gắng và sụp đổ dưới đây:

int main(int argc, char **argv) 
{ 
    // Get the hard and soft limit from command line 
    struct rlimit new = {atoi(argv[1]), atoi(argv[1])}; 

    // Create some memory so as to beef up the core file size 
    void *p = malloc(10 * 1024 * 1024); 

    if (!p) 
     return 1; 

    if (setrlimit(RLIMIT_CORE, &new)) // Set the hard and soft limit 
     return 2;      // for core files produced by this 
             // process 

    while (1); 

    free(p); 
    return 0; 
} 

Và đây là việc thực hiện:

Linux# ./a.out 1446462 & ## Set hard and soft limit to ~1.4 MB 
[1] 14802 
Linux# ./a.out 1446462 & 
[2] 14803 
Linux# ./a.out 1446462 & 
[3] 14804 
Linux# ./a.out 1446462 & 
[4] 14807 

Linux# cat /proc/14802/limits | grep core 
Max core file size  1446462    1446462    bytes 

Linux# killall -QUIT a.out 

Linux# ls -l 
total 15708 
-rwxr-xr-x 1 root root  4624 Aug 1 18:28 a.out 
-rw------- 1 root root 12013568 Aug 1 18:39 core.14802   <=== truncated core 
-rw------- 1 root root 12017664 Aug 1 18:39 core.14803 
-rw------- 1 root root 12013568 Aug 1 18:39 core.14804   <=== truncated core 
-rw------- 1 root root 12017664 Aug 1 18:39 core.14807 
[1] Quit     (core dumped) ./a.out 1446462 
[2] Quit     (core dumped) ./a.out 1446462 
[3] Quit     (core dumped) ./a.out 1446462 
[4] Quit     (core dumped) ./a.out 1446462 

Vì vậy, nhiều điều đã xảy ra ở đây. Tôi đặt giới hạn cứng cho mỗi quá trình là khoảng 1,4 MB.

  1. Các tệp lõi được sản xuất vượt quá giới hạn đã đặt này. Tại sao?
  2. Và 2 trong số 4 tệp lõi được tạo ra bị cắt bớt, nhưng chính xác là 4096 byte. Những gì đang xảy ra ở đây?

Tôi biết tệp lõi chứa trong số những thứ khác, bộ nhớ đầy đủ và bộ nhớ heap được phân bổ. Không nên có khá nhiều liên tục cho một chương trình đơn giản như vậy (cho hay mất một vài byte nhiều nhất), do đó tạo ra một lõi nhất quán giữa nhiều trường hợp?

CHỈNH SỬA:

Sản lượng yêu cầu của du

Linux# du core.* 
1428 core.14802 
1428 core.14803 
1428 core.14804 
1428 core.14807 

Linux# du -b core.* 
12013568 core.14802 
12017664 core.14803 
12013568 core.14804 
12017664 core.14807 

Thêm memset() sau malloc() chắc chắn trị vì thứ trong, trong đó các tập tin cốt lõi bây giờ tất cả được cắt ngắn để 1449984 (vẫn còn 3522 byte vượt quá giới hạn).

Vậy tại sao các lõi quá lớn trước đây, chúng chứa những gì? Bất kể nó là gì, nó cũng không bị giới hạn của quá trình.

Chương trình mới này cho thấy một số hành vi thú vị cũng như:

Linux# ./a.out 12017664 & 
[1] 26586 
Linux# ./a.out 12017664 & 
[2] 26589 
Linux# ./a.out 12017664 & 
[3] 26590 
Linux# ./a.out 12017663 &  ## 1 byte smaller 
[4] 26653 
Linux# ./a.out 12017663 &  ## 1 byte smaller 
[5] 26666 
Linux# ./a.out 12017663 &  ## 1 byte smaller 
[6] 26667 

Linux# killall -QUIT a.out 

Linux# ls -l 
total .. 
-rwxr-xr-x 1 root root  4742 Aug 1 19:47 a.out 
-rw------- 1 root root 12017664 Aug 1 19:47 core.26586 
-rw------- 1 root root 12017664 Aug 1 19:47 core.26589 
-rw------- 1 root root 12017664 Aug 1 19:47 core.26590 
-rw------- 1 root root 1994752 Aug 1 19:47 core.26653   <== ??? 
-rw------- 1 root root 9875456 Aug 1 19:47 core.26666   <== ??? 
-rw------- 1 root root 9707520 Aug 1 19:47 core.26667   <== ??? 
[1] Quit     (core dumped) ./a.out 12017664 
[2] Quit     (core dumped) ./a.out 12017664 
[3] Quit     (core dumped) ./a.out 12017664 
[4] Quit     (core dumped) ./a.out 12017663 
[5] Quit     (core dumped) ./a.out 12017663 
[6] Quit     (core dumped) ./a.out 12017663 
+0

Trước tiên, điều gì sẽ hiển thị cho số byte thực tế được sử dụng bởi tệp lõi? Ngoài ra, 'memset()' bộ nhớ. Việc thực hiện một 'malloc()' đơn giản không làm cho bộ nhớ thực được ánh xạ vào trong tiến trình. –

+0

4096 là kích thước trang bộ nhớ ảo. Khi kết xuất lõi được tạo, tất cả các trang vm được gán cho quá trình sẽ được đổ vào tệp lõi. Tệp nhỏ hơn là 2933 trang và tệp lớn hơn là 2934 trang. Vì vậy, đó là khá nhất quán. – user3386109

+0

@AndrewHenle Thêm 'memset()' chắc chắn làm mọi thứ nhất quán hơn, nhưng không hoàn toàn. Tôi đã cập nhật câu hỏi của tôi với kết quả đó và 'du'. – Ram

Trả lời

7

Việc thực hiện các lõi bán phá giá có thể được tìm thấy trong fs/binfmt_elf.c. Tôi sẽ thực hiện theo các mã trong 3,12 và ở trên (nó thay đổi với commit 9b56d5438) nhưng logic là rất giống nhau.

Mã ban đầu quyết định số lượng đổ VMA (vùng bộ nhớ ảo) trong vma_dump_size. Đối với một VMA ẩn danh chẳng hạn như vùng heap brk, nó trả về kích thước đầy đủ của VMA. Trong bước này, giới hạn lõi không liên quan.

Giai đoạn đầu tiên của việc viết kết xuất lõi sau đó viết tiêu đề PT_LOAD cho mỗi VMA. Điều này về cơ bản là một con trỏ cho biết nơi để tìm dữ liệu trong phần còn lại của tập tin ELF. Dữ liệu thực tế được viết bởi một vòng lặp for và thực sự là giai đoạn thứ hai.

Trong giai đoạn thứ hai, elf_core_dump liên tục gọi get_dump_page để nhận con trỏ struct page cho mỗi trang của không gian địa chỉ chương trình phải được bán phá giá. get_dump_page là một chức năng tiện ích phổ biến được tìm thấy trong mm/gup.c. Các bình luận cho get_dump_page là hữu ích:

* Returns NULL on any kind of failure - a hole must then be inserted into 
* the corefile, to preserve alignment with its headers; and also returns 
* NULL wherever the ZERO_PAGE, or an anonymous pte_none, has been found - 
* allowing a hole to be left in the corefile to save diskspace. 

và trong thực tế elf_core_dump gọi một hàm trong fs/coredump.c (dump_seek trong kernel, dump_skip trong 3.12+) nếu get_dump_page lợi nhuận NULL. Hàm này gọi lseek để lại một lỗ trong bãi chứa (thực tế vì đây là hạt nhân nó gọi file->f_op->llseek trực tiếp trên con trỏ struct file). Sự khác biệt chính là dump_seek thực sự không tuân theo ulimit, trong khi dump_skip mới hơn.

Vì lý do chương trình thứ hai có hành vi lạ, có thể do ASLR (ngẫu nhiên địa chỉ). VMA nào bị cắt bớt phụ thuộc vào thứ tự tương đối của các VMA, đó là ngẫu nhiên. Bạn có thể thử tắt tính năng này với

echo 0 | sudo tee /proc/sys/kernel/randomize_va_space 

và xem kết quả của bạn có đồng nhất hơn không. Để kích hoạt lại ASLR, hãy sử dụng

echo 2 | sudo tee /proc/sys/kernel/randomize_va_space 
Các vấn đề liên quan