为什么 ioctl 调用没有传递给 sys_ioctl?

Why is ioctl call not passed to sys_ioctl?

我有内核模块(4.4.32 内核),它通过将它的 ioctl 处理程序分配给 struct file_operationsunlocked_ioctl 指针来实现 ioctl 调用。一切正常,但我得到了程序(仅限二进制),为 2.6 或 2.4 内核编译,如果我在 4.4.32 上启动该程序,它不会使内核为我的模块注册对 ioctl 的调用。 因为该程序是在较旧的内核上编译的,所以它使用较旧的 ioctl 接口,即 file_operations 结构中的 ioctl 指针,而不是 unlocked_ioctl.

较旧的程序会创建一个控制台,用于与用户进行可视化交互,并且必须 运行 作为根控制台的根用户。

我对该程序进行了 strace 并检查该程序是否收到 ENOTTY 用于第二个 ioctl,因此我编写了测试程序,该程序对内核模块进行与故障程序相同的 ioctl 调用。

我已验证 strace 记录的跟踪对于这些 ioctl 的两个程序是相同的,即它们以相同的参数以相同的顺序调用。

我的测试程序的相关部分是:

/*--------------------------- ((( STEP 1 ))) ---------------------------*/
hsdfd1 = open(PCIHSD0, O_RDWR);
if (hsdfd1 < 0) {
    fprintf(stderr, "Error on OPEN, can't open [%s] [%s]", PCIHSD0, strerror(errno));
    exit(1);
}

/*--------------------------- ((( STEP 2 ))) ---------------------------*/
uint8_t xsts;
err = ioctl(hsdfd1, HSDGETXSTS, &xsts);
if (err < 0) {
    fprintf(stderr, "Error HSDGETXSTS [%s]", strerror(errno));
    close(hsdfd1);
    exit(2);
}

/*--------------------------- ((( STEP 3 ))) ---------------------------*/
hsdfd2 = open(PCIHSD0c, O_NDELAY, O_RDONLY);
if (hsdfd2 < 0) {
    fprintf(stderr, "Error on OPEN, can't open [%s] [%s]", PCIHSD0c, strerror(errno));
    close(hsdfd1);
    exit(3);
}

/*--------------------------- ((( STEP 4 ))) ---------------------------*/
err = ioctl(hsdfd2, PCIHSD_DIAG_SETALLOWDC, 0x1);
if (err < 0) {
    fprintf(stderr, "Error PCIHSD_DIAG_SETALLOWDC [%s]", strerror(errno));
    err = 4;
    goto exit;
}

痕迹:

我的测试程序:

execve("./hsddebug", ["./hsddebug"], [/* 23 vars */]) = 0
brk(0)                                  = 0xb89000
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) = 0x7f9231c6b000
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=105359, ...}) = 0
mmap(NULL, 105359, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f9231c51000
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, "7ELF[=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=][=12=]>[=12=][=12=][=12=][=12=]P[=12=][=12=][=12=][=12=][=12=]"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1738176, ...}) = 0
mmap(NULL, 3844640, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f92316a2000
mprotect(0x7f9231843000, 2097152, PROT_NONE) = 0
mmap(0x7f9231a43000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1a1000) = 0x7f9231a43000
mmap(0x7f9231a49000, 14880, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f9231a49000
close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9231c50000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9231c4f000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9231c4e000
arch_prctl(ARCH_SET_FS, 0x7f9231c4f700) = 0
mprotect(0x7f9231a43000, 16384, PROT_READ) = 0
mprotect(0x7f9231c6d000, 4096, PROT_READ) = 0
munmap(0x7f9231c51000, 105359)          = 0
rt_sigaction(SIGINT, {0x400826, [INT], SA_RESTORER|SA_RESTART, 0x7f92316d70e0}, {SIG_DFL, [], 0}, 8) = 0
open("/dev/pcihsd0", O_RDWR)            = 3
ioctl(3, PHN_GETREG or RTC_PIE_ON, 0x7ffec60e3643) = 0
open("/dev/pcihsd0c", O_RDONLY|O_NONBLOCK) = 4
ioctl(4, 0x70c0, 0x1)                   = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9231c6a000
write(1, "\n", 1)                       = 1
write(1, "OK\n", 3)                     = 3
close(3)                                = 0
close(4)                                = 0
exit_group(0)                           = ?
+++ exited with 0 +++

故障程序:

execve("./pcihsd", ["./pcihsd"], [/* 18 vars */]) = 0
uname({sys="Linux", node="debian", ...}) = 0
brk(0)                                  = 0x83bb000
brk(0x83dc000)                          = 0x83dc000
rt_sigaction(SIGINT, {0x804848f, [INT], SA_RESTORER|SA_RESTART, 0x806ab28}, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGQUIT, {0x804842b, [QUIT], SA_RESTORER|SA_RESTART, 0x806ab28}, {SIG_DFL, [], 0}, 8) = 0
open("PCIHSD.hlp", O_RDONLY)            = 3
old_mmap(NULL, 266240, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xfffffffff76d7000
ioctl(1, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
access("/root/.terminfo/l/linux-fk", R_OK) = -1 ENOENT (No such file or directory)
access("/usr/share/terminfo/l/linux-fk", R_OK) = 0
open("/usr/share/terminfo/l/linux-fk", O_RDONLY) = 4
read(4, "/[=13=][=13=][=13=]}a", 12) = 12
read(4, "linux-fk|linux console with sF9 "..., 47) = 47
read(4, "[=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=][=13=]", 29) = 29
read(4, "77[=13=]7777777777777777777777[=13=]@[=13=][=13=]", 32) = 32
read(4, "77[=13=][=13=][=13=][=13=][=13=][=13=]![=13=]%[=13=])[=13=]774[=13=]E[=13=]G[=13=]K[=13=]W[=13=]77"..., 762) = 762
read(4, "[=13=]\r[=13=][%i%p1%d;%p2%dr[=13=][3g[=13=][H[J"..., 865) = 865
read(4, "", 1)                          = 0
read(4, "", 10)                         = 0
close(4)                                = 0
ioctl(1, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(1, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(1, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(1, TIOCGWINSZ, {ws_row=64, ws_col=160, ws_xpixel=0, ws_ypixel=0}) = 0
ioctl(1, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(1, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
brk(0x83fd000)                          = 0x83fd000
ioctl(1, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(1, SNDCTL_TMR_STOP or SNDRV_TIMER_IOCTL_GINFO or TCSETSW, {B38400 opost isig -icanon echo ...}) = 0
ioctl(1, SNDCTL_TMR_STOP or SNDRV_TIMER_IOCTL_GINFO or TCSETSW, {B38400 opost isig -icanon -echo ...}) = 0
rt_sigaction(SIGTSTP, NULL, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGTSTP, {0x805d130, [], SA_RESTORER|SA_RESTART, 0x806ab28}, NULL, 8) = 0
rt_sigaction(SIGINT, NULL, {0x804848f, [INT], SA_RESTORER|SA_RESTART, 0x806ab28}, 8) = 0
rt_sigaction(SIGTERM, NULL, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGTERM, {0x805d310, [], SA_RESTORER|SA_RESTART, 0x806ab28}, NULL, 8) = 0
rt_sigaction(SIGWINCH, NULL, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGWINCH, {0x805d410, [], SA_RESTORER, 0x806ab28}, NULL, 8) = 0
ioctl(1, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, {B38400 opost isig -icanon -echo ...}) = 0
ioctl(1, SNDCTL_TMR_STOP or SNDRV_TIMER_IOCTL_GINFO or TCSETSW, {B38400 opost isig -icanon -echo ...}) = 0
write(1, "[1;64r[0;10m[4l[?7h[?25h[?"..., 34) = 34
rt_sigaction(SIGTSTP, {SIG_IGN, [], SA_RESTORER|SA_RESTART, 0x806ab28}, {0x805d130, [], SA_RESTORER|SA_RESTART, 0x806ab28}, 8) = 0
write(1, "[H[J[24d", 11)       = 11
rt_sigaction(SIGTSTP, {0x805d130, [], SA_RESTORER|SA_RESTART, 0x806ab28}, NULL, 8) = 0
write(1, "[?25l[?1c", 11)         = 11
open("PCIHSD.dft", O_RDONLY)            = -1 ENOENT (No such file or directory)
open("/dev/pcihsd0", O_RDWR)            = 4
ioctl(4, PHN_GETREG or RTC_PIE_ON, 0x80cd480) = 0
rt_sigaction(SIGALRM, {0x804950f, [], SA_RESTORER|SA_INTERRUPT|SA_NODEFER|SA_RESETHAND, 0x806ab28}, {SIG_DFL, [], 0}, 8) = 0
open("/dev/pcihsd0c", O_RDONLY|O_NONBLOCK) = 5
ioctl(5, 0x70c0, 0x1)                   = -1 ENOTTY (Inappropriate ioctl for device)
close(4)                                = 0
close(5)                                = 0

如您所见,在这两种情况下,相关的 ioctl 调用是相同的,即:

open("/dev/pcihsd0", O_RDWR)            = descriptor1
ioctl(descriptor1, PHN_GETREG or RTC_PIE_ON, 0x7ffec60e3643) = 0
open("/dev/pcihsd0c", O_RDONLY|O_NONBLOCK) = descriptor2
ioctl(descriptor2, 0x70c0, 0x1)                   = 0/ENOTTY ???

问题 1:

第二次调用 ioctl(使用 cmd 0x70c0)没有得到内核的 sys_ioctl/vfs_ioctl 函数调用(旧)故障程序执行时调用的原因是什么(我有一个断点在 运行ning 内核上设置 - 调用未被内核记录,即使正确记录了对第一个 ioctl 的调用并且两个程序都命中了断点)?

问题 2:

在哪里插入断点来调试这个?为什么我在故障程序案例中根本看不到 sys_ioctl 被调用?


编辑:

感谢 Wumpus Q. Wumbley 对问题 1 的回答。

问题 2 的答案是:

当驱动程序实现 compat_ioctl 时,将调用 compat_SyS_ioctl 而不是 compat_ioctl。它是从 do_syscall32_irqs_on/do_syscall_32_irqs_off 调用的,它们是从 entry_INT80_compat 调用的。 sys32_pread/SyS_pread64entry_INT80_compat 调用 struct file_operationread 处理程序。

strace 结果中的不同指针值,我可以看出有效的是 64 位程序,而给出 ENOTTY 的是 32 位程序。

您需要定义一个compat_ioctl以使您的驱动程序支持32位程序。