Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

fork() succeeds with a descriptor missing when its pin cannot be allocated

Đang mở Phù hợp với người mới
#414 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 2 ngày

Chưa có ai nhận issue này.

Đánh giá

Độ khó
2/5
Thời gian dự kiến
1-3 giờ
Mức phù hợp với người mới
75/100
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
c
Lĩnh vực
operating-systems

Hướng nghiên cứu

Bắt đầu từ src/runtime/fork-state.c tại fork_ipc_send_fd_table() để xem cách nó xử lý giá trị trả về NULL từ fd_lifetime_pin_locked(). Sau đó kiểm tra src/syscall/fdtable.c để tìm fd_lifetime_pin_spare() và hiểu các trường hợp lỗi cấp phát. Bản sửa lỗi phải làm cho fork() trả về -1 kèm ENOMEM khi không thể cấp phát pin, và bạn có thể xác minh bằng cách sử dụng quy trình tái tạo bằng injection lỗi được mô tả.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

bug

fork_ipc_send_fd_table() (src/runtime/fork-state.c) skips a slot when fd_lifetime_pin_locked() returns NULL:

pin = fd_lifetime_pin_locked(i);
if (!pin)
    continue;

fd_lifetime_pin_spare() returns NULL for a closed slot, for a slot with no host descriptor, and when malloc fails. The loop has already skipped FD_CLOSED under the same fd_lock hold, so on an open slot with a host descriptor NULL means the allocation failed. The slot is then left out of the table sent to the child, the send completes, and the parent's fork() returns the child pid. Nothing is logged.

Linux fork() either gives the child every descriptor or fails with ENOMEM.

Reproduction

The allocation cannot be made to fail from the guest, so this uses fault injection on b57f367. In fd_lifetime_pin_spare() (src/syscall/fdtable.c):

-            lifetime = malloc(sizeof(*lifetime));
+            lifetime = (fd == 5 && getenv("PINFAIL"))
+                           ? NULL
+                           : malloc(sizeof(*lifetime));

Guest:

for (int i = 0; i < 5; i++)
    open("/dev/null", O_RDONLY); /* fds 3..7 */
pid_t pid = fork();
printf("[%s] fork returned %d\n", pid ? "parent" : "child", (int) pid);
if (pid == 0) {
    for (int fd = 3; fd <= 7; fd++)
        printf("child fd %d: %s\n", fd,
               fcntl(fd, F_GETFD) >= 0 ? "open" : strerror(errno));
    _exit(0);
}
waitpid(pid, NULL, 0);

With PINFAIL=1:

[parent] fork returned 2
[child] fork returned 0
child fd 3: open
child fd 4: open
child fd 5: Bad file descriptor
child fd 6: open
child fd 7: open

Without the variable, fd 5 is open in the child.

Expected

fork() returns -1 with ENOMEM and no child is left running.

The skip is older than the pin. At 628181b, where this loop still calls dup(), a guest holding 1021 descriptors under ulimit -n 1280 gets a successful fork() and a child with descriptors missing.

Ngôn ngữ chính
C
Star
271
Fork
28
Merge trung bình
2 ngày 18 giờ
Pull request đã merge (30 ngày)
19

Chuẩn bị môi trường

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của sysprog21/elfuse

Tất cả issue của sysprog21/elfuse

Issue tương tự

Thêm issue về C

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.