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

`/dev/fd` lists the elfuse process's descriptors, not the guest's

Đang mở
#405 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ó
3/5
Thời gian dự kiến
1-2 ngày
Mức phù hợp với người mới
78/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

Start in src/syscall/path.c:91 and follow proc_intercept_open in src/runtime/procemu.c:3727 to the /dev/fd/ arm at src/runtime/procemu.c:2382. Read proc_open_fd_scratch at src/runtime/procemu.c:550, then run the supplied reproducer and the test-path-fold coverage from #398. Done means /dev/fd lists and opens the guest's descriptors consistently with /proc/self/fd.

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

Mô tả

Symptom

Measured on 2c4a8f4, macOS 15.6.1, Apple M1. Three runs of each, identical, and the same with --sysroot on the Alpine rootfs, which carries no /dev/fd:

held: 0 1 2 3 50, plus the descriptor each listing reads through
/dev/fd, read through 4, lists: 0 1 2 3 4 5 6 7 8 9
  of those, not openable as /dev/fd/N: 5 6 7 8 9
/proc/self/fd, read through 128, lists: 50 0 1 3 2
  of those, not openable as /dev/fd/N: none
/dev/fd is a directory

The /dev/fd listing is the descriptor table of the elfuse process on the host. It shares 0 through 4 with the guest's, but it omits 50, which the guest holds, and lists 5 through 9, which the guest cannot open by those names. /proc/self/fd lists the guest's table, less the descriptor it is read through (below).

Linux itself provides no /dev/fd, and the reference boot has none. Userspace creates it as a symlink to /proc/self/fd. With that symlink in place, Linux 6.18.54-0-virt through the qemu reference lane:

held: 0 1 2 3 50, plus the descriptor each listing reads through
/dev/fd, read through 4, lists: 0 1 2 3 4 50
  of those, not openable as /dev/fd/N: none
/proc/self/fd, read through 4, lists: 0 1 2 3 4 50
  of those, not openable as /dev/fd/N: none
/dev/fd is a symlink

Because the listing is host state, it moves with things the guest does not do. With three instances of test-path-fold, as first pushed to #398, running at once, two adjacent listings of /dev/fd differed in 11 of 45 runs. That turned Runtime (Release) red once on that PR: getdents /dev/fd/: 13 entries, want 12 entries.

Reproducer

#include <dirent.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>

/* Print what @dir lists, then which of the listed numbers do not open as
 * /dev/fd/N. The listing stays open while the numbers are tried, so its own
 * descriptor is one of the held ones.
 */
static void list(const char *dir) {
  DIR *d = opendir(dir);
  if (!d) {
    perror(dir);
    return;
  }
  int listed[64], n = 0;
  struct dirent *e;
  while ((e = readdir(d)) && n < 64)
    if (e->d_name[0] != '.')
      listed[n++] = atoi(e->d_name);

  printf("%s, read through %d, lists:", dir, dirfd(d));
  for (int i = 0; i < n; i++)
    printf(" %d", listed[i]);
  printf("\n  of those, not openable as /dev/fd/N:");
  int none = 1;
  for (int i = 0; i < n; i++) {
    char path[32];
    snprintf(path, sizeof(path), "/dev/fd/%d", listed[i]);
    int fd = open(path, O_RDONLY | O_NONBLOCK);
    if (fd >= 0) {
      close(fd);
    } else {
      printf(" %d", listed[i]);
      none = 0;
    }
  }
  printf("%s\n", none ? " none" : "");
  closedir(d);
}

int main(void) {
  int a = open("/", O_RDONLY | O_DIRECTORY);
  dup2(1, 50);
  printf("held: 0 1 2 %d 50, plus the descriptor each listing reads through\n",
         a);
  list("/dev/fd");
  list("/proc/self/fd");

  struct stat st;
  lstat("/dev/fd", &st);
  printf("/dev/fd is a %s\n", S_ISLNK(st.st_mode)   ? "symlink"
                              : S_ISDIR(st.st_mode) ? "directory"
                                                    : "?");
  return 0;
}

Mechanism

path_might_use_open_intercept admits every /dev name (src/syscall/path.c:91). proc_intercept_open (src/runtime/procemu.c:3727) hands it to intercept_open_dispatch, which has an arm for /dev/fd/<N> (src/runtime/procemu.c:2382) that dups the guest's descriptor N, and none for /dev/fd itself. The open of the directory falls through to the host, where macOS serves /dev/fd from devfs as a directory of the calling process's descriptors, which are elfuse's. The listing and the lookup therefore answer from two different descriptor tables.

Direction

Serving /dev/fd as the symlink Linux userspace creates, to /proc/self/fd, makes the listing the guest's and keeps it in agreement with /dev/fd/<N>, which already answers from the guest's table.

One difference would carry over, visible above. The synthetic /proc/self/fd does not list the descriptor the listing is read through (128 on elfuse, 4 on Linux). proc_open_fd_scratch (src/runtime/procemu.c:550) snapshots the table when the directory is opened, before that descriptor exists.

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.