为什么......在syscall中使用与之前打开的dirfd不同的dirfd?

时间:2016-02-16 12:29:31

标签: c linux linux-kernel

使用"#import ViewController.h"我正在打印所有打开的文件描述符,但LD_PRELOAD系统调用程序使用不同的文件描述符。为什么呢?

最简单的例子:

这是我的库...at - 它拦截所有foobar.c调用并打印文件描述符,并打印调用open...

的参数
unlinkat

我没有包含#define _GNU_SOURCE #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <dlfcn.h> #include <stdio.h> #include <unistd.h> int open(const char *pathname, int flags, ...) { int fd = ((int (*) (const char*, int, ...))dlsym(RTLD_NEXT, "open"))(pathname, flags); printf("open pathname %s fd %d\n", pathname, fd); return fd; } int open64(const char *pathname, int flags, ...) { int fd = ((int (*) (const char*, int, ...))dlsym(RTLD_NEXT, "open64"))(pathname, flags); printf("open64 pathname %s fd %d\n", pathname, fd); return fd; } int openat(int dirfd, const char* pathname, int flags, ...) { int fd = ((int (*) (int, const char*, int, ...))dlsym(RTLD_NEXT, "openat"))(dirfd, pathname, flags); printf("openat pathname %s fd %d\n", pathname, fd); return fd; } int unlinkat(int dirfd, const char *pathname, int flags) { printf("unlinkat dirfd %d pathname %s\n", dirfd, pathname); return ((int (*) (int, const char*, int))dlsym(RTLD_NEXT, "unlinkat"))(dirfd, pathname, flags); } 拦截来保持简单,不会被调用。

现在注意到库工作正常,我捕获所有打开的文件描述符,它们都等于3,但是,打开的文件描述符相对于dup被调用,是4.为什么?

unlinkat

1 个答案:

答案 0 :(得分:5)

[mitalia@mitalia /tmp]$ mkdir -p dir/dir1
[mitalia@mitalia /tmp]$ strace rm -rf dir
execve("/bin/rm", ["rm", "-rf", "dir"], [/* 76 vars */]) = 0
brk(0)                                  = 0x1538000
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) = 0x7f4c779a2000
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=211009, ...}) = 0
mmap(NULL, 211009, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f4c7796e000
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\320\37\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1840928, ...}) = 0
mmap(NULL, 3949248, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f4c773bd000
mprotect(0x7f4c77578000, 2093056, PROT_NONE) = 0
mmap(0x7f4c77777000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1ba000) = 0x7f4c77777000
mmap(0x7f4c7777d000, 17088, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f4c7777d000
close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f4c7796d000
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f4c7796b000
arch_prctl(ARCH_SET_FS, 0x7f4c7796b740) = 0
mprotect(0x7f4c77777000, 16384, PROT_READ) = 0
mprotect(0x60d000, 4096, PROT_READ)     = 0
mprotect(0x7f4c779a4000, 4096, PROT_READ) = 0
munmap(0x7f4c7796e000, 211009)          = 0
brk(0)                                  = 0x1538000
brk(0x1559000)                          = 0x1559000
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=5766672, ...}) = 0
mmap(NULL, 5766672, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f4c76e3d000
close(3)                                = 0
ioctl(0, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
lstat("/", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
newfstatat(AT_FDCWD, "dir", {st_mode=S_IFDIR|0775, st_size=4096, ...}, AT_SYMLINK_NOFOLLOW) = 0
openat(AT_FDCWD, "dir", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_DIRECTORY|O_NOFOLLOW) = 3
fstat(3, {st_mode=S_IFDIR|0775, st_size=4096, ...}) = 0
fcntl(3, F_GETFL)                       = 0x38800 (flags O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY|O_NOFOLLOW)
fcntl(3, F_SETFD, FD_CLOEXEC)           = 0
getdents(3, /* 3 entries */, 32768)     = 72
close(3)                                = 0
openat(AT_FDCWD, "dir", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_DIRECTORY|O_NOFOLLOW) = 3
fcntl(3, F_GETFD)                       = 0
fcntl(3, F_SETFD, FD_CLOEXEC)           = 0
fstat(3, {st_mode=S_IFDIR|0775, st_size=4096, ...}) = 0
fcntl(3, F_GETFL)                       = 0x38800 (flags O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY|O_NOFOLLOW)
fcntl(3, F_SETFD, FD_CLOEXEC)           = 0
fcntl(3, F_DUPFD, 3)                    = 4
fcntl(4, F_GETFD)                       = 0
fcntl(4, F_SETFD, FD_CLOEXEC)           = 0
getdents(3, /* 3 entries */, 32768)     = 72
getdents(3, /* 0 entries */, 32768)     = 0
close(3)                                = 0
newfstatat(4, "dir1", {st_mode=S_IFDIR|0775, st_size=4096, ...}, AT_SYMLINK_NOFOLLOW) = 0
openat(4, "dir1", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_DIRECTORY|O_NOFOLLOW) = 3
fstat(3, {st_mode=S_IFDIR|0775, st_size=4096, ...}) = 0
fcntl(3, F_GETFL)                       = 0x38800 (flags O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY|O_NOFOLLOW)
fcntl(3, F_SETFD, FD_CLOEXEC)           = 0
getdents(3, /* 2 entries */, 32768)     = 48
getdents(3, /* 0 entries */, 32768)     = 0
close(3)                                = 0
unlinkat(4, "dir1", AT_REMOVEDIR)       = 0
close(4)                                = 0
unlinkat(AT_FDCWD, "dir", AT_REMOVEDIR) = 0
lseek(0, 0, SEEK_CUR)                   = -1 ESPIPE (Illegal seek)
close(0)                                = 0
close(1)                                = 0
close(2)                                = 0
exit_group(0)                           = ?
+++ exited with 0 +++

在我的系统上,文件描述符4是由fcntl返回的F_DUPFD调用的文件描述符,它是dup2的近亲;我也期待你的事情发生类似的事情。

通常,如果要监视文件描述符创建,还必须监视文件描述符复制函数(dupdup2dup3,{ {1}} fcntl以及其他我不知道的人。

另外,请记住,F_DUPFD技巧仅挂钩C库函数,应用程序仍然可以自由执行&#34; raw&#34;系统调用(x86上的LD_PRELOAD,x86_64上的int 0x80以及其他平台上的任何内容),你没有注意到。可靠地监控所有这些东西的最可靠方法是使用(可怕的)sysenter界面(ptrace请求应该是你的朋友),顺便提一下PTRACE_SYSCALLstrace实现。