C 获取一个与内核中的任何内容都不相关的唯一文件描述符

C 获取一个与内核中的任何内容都不相关的唯一文件描述符,c,linux,mocking,C,Linux,Mocking,我正在寻找一种方法来为一个进程获取一个唯一的文件描述符,该进程与任何特定的内容都没有关联。它必须是唯一的整数,内核不会为其创建等效的文件描述符 到目前为止,我只是打开/dev/null以获取唯一的文件描述符编号。我想知道是否有人知道实现这一点的更好方法(例如,某种“create\u fd()”系统调用)。在POSIX上: unsigned maxfd = sysconf(_SC_OPEN_MAX); unsigned nulfd = maxfd + 1; 注意使用了unsigned,这样当sy

我正在寻找一种方法来为一个进程获取一个唯一的文件描述符,该进程与任何特定的内容都没有关联。它必须是唯一的整数,内核不会为其创建等效的文件描述符

到目前为止,我只是打开
/dev/null
以获取唯一的文件描述符编号。我想知道是否有人知道实现这一点的更好方法(例如,某种“
create\u fd()
”系统调用)。

在POSIX上:

unsigned maxfd = sysconf(_SC_OPEN_MAX);
unsigned nulfd = maxfd + 1;

注意使用了
unsigned
,这样当
sysconf()
返回
INT\u MAX

时,我们就不会溢出。您可以通过ioctl()或使用proc文件创建模块并添加模拟文件描述符创建。文件描述符表仅存在于监控模式(内核中)。我不明白,如果不创建一个新的内核模块,或者不重用一个恰好满足您需要的内核模块,您如何能够保留它

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>

#define procfs_name "always_fail"

struct proc_dir_entry *proc_file;

int procfile_read(char *buffer,
          char **buffer_location,
          off_t offset, int buffer_length, int *eof, void *data)
{   
    printk(KERN_INFO "procfile_read (/proc/%s) called\n", procfs_name);

    return -1;
}

int init_module()
{
    proc_file = create_proc_entry(procfs_name, 0644, NULL);

    if (proc_file == NULL) {
        remove_proc_entry(procfs_name, &proc_root);
        printk(KERN_ALERT "Error: Could not initialize /proc/%s\n",
               procfs_name);
        return -ENOMEM;
    }

    proc_file->read_proc     = procfile_read;
    proc_file->owner         = THIS_MODULE;
    proc_file->mode          = S_IFREG | S_IRUGO;
    proc_file->uid           = 0;
    proc_file->gid           = 0;
    proc_file->size          = 0;

    printk(KERN_INFO "/proc/%s created\n", procfs_name);    
    return 0;
}

void cleanup_module()
{
    remove_proc_entry(procfs_name, &proc_root);
    printk(KERN_INFO "/proc/%s removed\n", procfs_name);
}
有关详细信息,请参阅内核源代码和内部任务结构(进程描述符)

这里有一个proc文件系统模块,它可以做您想做的事情

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>

#define procfs_name "always_fail"

struct proc_dir_entry *proc_file;

int procfile_read(char *buffer,
          char **buffer_location,
          off_t offset, int buffer_length, int *eof, void *data)
{   
    printk(KERN_INFO "procfile_read (/proc/%s) called\n", procfs_name);

    return -1;
}

int init_module()
{
    proc_file = create_proc_entry(procfs_name, 0644, NULL);

    if (proc_file == NULL) {
        remove_proc_entry(procfs_name, &proc_root);
        printk(KERN_ALERT "Error: Could not initialize /proc/%s\n",
               procfs_name);
        return -ENOMEM;
    }

    proc_file->read_proc     = procfile_read;
    proc_file->owner         = THIS_MODULE;
    proc_file->mode          = S_IFREG | S_IRUGO;
    proc_file->uid           = 0;
    proc_file->gid           = 0;
    proc_file->size          = 0;

    printk(KERN_INFO "/proc/%s created\n", procfs_name);    
    return 0;
}

void cleanup_module()
{
    remove_proc_entry(procfs_name, &proc_root);
    printk(KERN_INFO "/proc/%s removed\n", procfs_name);
}
另一种黑客方式是简单地使用
/dev/net/tun
,假设您拥有它。它将在读写时失败,但在打开时不会失败

证明:

$ sudo strace cat /dev/net/tun 
execve("/bin/cat", ["cat", "/dev/net/tun"], [/* 18 vars */]) = 0
brk(0)                                  = 0x24c5000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f83fed22000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=128879, ...}) = 0
mmap(NULL, 128879, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f83fed02000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\260\37\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1848024, ...}) = 0
mmap(NULL, 3961912, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f83fe73a000
mprotect(0x7f83fe8f8000, 2093056, PROT_NONE) = 0
mmap(0x7f83feaf7000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1bd000) = 0x7f83feaf7000
mmap(0x7f83feafd000, 17464, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f83feafd000
close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f83fed01000
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f83fecff000
arch_prctl(ARCH_SET_FS, 0x7f83fecff740) = 0
mprotect(0x7f83feaf7000, 16384, PROT_READ) = 0
mprotect(0x60a000, 4096, PROT_READ)     = 0
mprotect(0x7f83fed24000, 4096, PROT_READ) = 0
munmap(0x7f83fed02000, 128879)          = 0
brk(0)                                  = 0x24c5000
brk(0x24e6000)                          = 0x24e6000
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=7220496, ...}) = 0
mmap(NULL, 7220496, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f83fe057000
close(3)                                = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0
**open("/dev/net/tun", O_RDONLY)          = 3**
fstat(3, {st_mode=S_IFCHR|S_ISVTX|0666, st_rdev=makedev(10, 200), ...}) = 0
fadvise64(3, 0, 0, POSIX_FADV_SEQUENTIAL) = 0
**read(3, 0x24c7000, 65536)               = -1 EBADFD (File descriptor in bad state)**
write(2, "cat: ", 5cat: )                    = 5
write(2, "/dev/net/tun", 12/dev/net/tun)            = 12
open("/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 4
fstat(4, {st_mode=S_IFREG|0644, st_size=2570, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f83fed21000
read(4, "# Locale name alias data base.\n#"..., 4096) = 2570
read(4, "", 4096)                       = 0
close(4)                                = 0
munmap(0x7f83fed21000, 4096)            = 0
open("/usr/share/locale/en_CA/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/en/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale-langpack/en_CA/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale-langpack/en/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
write(2, ": File descriptor in bad state", 30: File descriptor in bad state) = 30
write(2, "\n", 1
)                       = 1
**close(3)                                = 0**
close(1)                                = 0
close(2)                                = 0
exit_group(1)                           = ?
eric@ideapad:~$ sudo strace cat /dev/net/tun 
execve("/bin/cat", ["cat", "/dev/net/tun"], [/* 18 vars */]) = 0
brk(0)                                  = 0x109f000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fdc6d3db000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=128879, ...}) = 0
mmap(NULL, 128879, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fdc6d3bb000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\260\37\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1848024, ...}) = 0
mmap(NULL, 3961912, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fdc6cdf3000
mprotect(0x7fdc6cfb1000, 2093056, PROT_NONE) = 0
mmap(0x7fdc6d1b0000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1bd000) = 0x7fdc6d1b0000
mmap(0x7fdc6d1b6000, 17464, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fdc6d1b6000
close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fdc6d3ba000
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fdc6d3b8000
arch_prctl(ARCH_SET_FS, 0x7fdc6d3b8740) = 0
mprotect(0x7fdc6d1b0000, 16384, PROT_READ) = 0
mprotect(0x60a000, 4096, PROT_READ)     = 0
mprotect(0x7fdc6d3dd000, 4096, PROT_READ) = 0
munmap(0x7fdc6d3bb000, 128879)          = 0
brk(0)                                  = 0x109f000
brk(0x10c0000)                          = 0x10c0000
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=7220496, ...}) = 0
mmap(NULL, 7220496, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fdc6c710000
close(3)                                = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0
open("/dev/net/tun", O_RDONLY)          = 3
fstat(3, {st_mode=S_IFCHR|S_ISVTX|0666, st_rdev=makedev(10, 200), ...}) = 0
fadvise64(3, 0, 0, POSIX_FADV_SEQUENTIAL) = 0
read(3, 0x10a1000, 65536)               = -1 EBADFD (File descriptor in bad state)
write(2, "cat: ", 5cat: )                    = 5
write(2, "/dev/net/tun", 12/dev/net/tun)            = 12
open("/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 4
fstat(4, {st_mode=S_IFREG|0644, st_size=2570, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fdc6d3da000
read(4, "# Locale name alias data base.\n#"..., 4096) = 2570
read(4, "", 4096)                       = 0
close(4)                                = 0
munmap(0x7fdc6d3da000, 4096)            = 0
open("/usr/share/locale/en_CA/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/en/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale-langpack/en_CA/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale-langpack/en/LC_MESSAGES/libc.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
write(2, ": File descriptor in bad state", 30: File descriptor in bad state) = 30
write(2, "\n", 1
)                       = 1
close(3)                                = 0
close(1)                                = 0
close(2)                                = 0
exit_group(1)                           = ?

您正在查找无效的文件描述符?为什么?@ElchononEdelson:为了“模拟”某些根本不涉及内核的I/O操作。创建一个套接字。不要绑定或连接它。管道也将执行相同的操作参见
man-A管道
@EricdesCourtis:Opening
/dev/null
更简单,并且执行相同的操作。我只是希望有一种方法可以简单地保留一个唯一的合法文件描述符,该描述符不与任何字符设备或文件关联,这样我不会截获的所有调用都会失败。请使用负数或大于当前打开文件限制的数。这两个都保证永远不会是有效的文件描述符。很酷,但在程序运行时,最大打开文件限制是否可能更改?@VladLazarenko。嗯,噢。看来到目前为止,
/dev/null
仍然是我最好的朋友。我曾考虑过一个“负”文件号,但它违反了POSIX标准,许多应用程序可能会干脆扔掉并拒绝使用它。这比使用
/dev/null
?@R..:因为如果出于某种原因,读/写绕过“mocking”库并实际执行系统调用,它会失败。使用
/dev/null
,read给出EOF,write总是成功。