2017-02-16 32 views
2

У меня есть модуль ядра (ядро 4.4.32), которое реализует вызов ioctl, назначая его обработчик ioctl на struct file_operationsunlocked_ioctl указатель. Все работает нормально, но мне была предоставлена ​​программа (только двоичная), скомпилированная для ядра 2.6 или 2.4, которая не заставляет ядро ​​регистрировать вызов ioctl для моего модуля, если я запускаю эту программу на моем 4.4.32. Поскольку эта программа была скомпилирована на старшем ядре, она использует более старый интерфейс ioctl, то есть ioctl указатель в структуре file_operations, а не unlocked_ioctl.Почему вызов ioctl не передается sys_ioctl?

Старая программа создает консоль для визуального взаимодействия с пользователем и должна запускаться как root из корневой консоли.

Я проверил эту программу и проверил, что программа получает ENOTTY для 2-го ioctl, поэтому я написал тестовую программу, которая делает те же самые вызовы ioctl для модуля ядра, который выполняет программа сбоя.

Я проверил, что трассировка, зарегистрированная strace, одинакова для обеих программ для этих ioctl, то есть thay вызывается с одинаковыми аргументами в той же последовательности.

Соответствующая часть моей тестовой программы:

/*--------------------------- (((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; 
} 

В straces:

Моя тестовая программа:

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, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\34\2\0\0\0\0\0"..., 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 +++ 

программа Fault:

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, "\32\1/\0\35\0\20\0}\1a\3", 12) = 12 
read(4, "linux-fk|linux console with sF9 "..., 47) = 47 
read(4, "\0\1\0\0\1\1\0\0\0\0\0\0\0\1\1\0\0\0\0\0\1\0\0\0\0\0\0\1\1", 29) = 29 
read(4, "\377\377\10\0\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\10\[email protected]\0\22\0", 32) = 32 
read(4, "\377\377\0\0\2\0\4\0\25\0\32\0!\0%\0)\0\377\3774\0E\0G\0K\0W\0\377\377"..., 762) = 762 
read(4, "\7\0\r\0\33[%i%p1%d;%p2%dr\0\33[3g\0\33[H\33[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, "\33[1;64r\33[0;10m\33[4l\33[?7h\33[?25h\33[?"..., 34) = 34 
rt_sigaction(SIGTSTP, {SIG_IGN, [], SA_RESTORER|SA_RESTART, 0x806ab28}, {0x805d130, [], SA_RESTORER|SA_RESTART, 0x806ab28}, 8) = 0 
write(1, "\33[H\33[J\33[24d", 11)  = 11 
rt_sigaction(SIGTSTP, {0x805d130, [], SA_RESTORER|SA_RESTART, 0x806ab28}, NULL, 8) = 0 
write(1, "\33[?25l\33[?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 ??? 

Question1:

Что может быть причиной того, что второй вызов IOCTL (что с CMD 0x70c0) не получает sys_ioctl/функции vfs_ioctl ядра еще вызванный, когда он выполняется (старой) программой сбоя (у меня установлена ​​точка останова на запущенном ядре - вызов не записывается ядром, даже если вызов первой ioctl правильно записан и точка останова удалена для обеих программ)?

Вопрос 2:

Где вставить точку останова для отладки это? Почему я вообще не вижу sys_ioctl в случае программы ошибок?


EDIT:

Благодаря Wumpus Q. Wumbley для ответа на Question1.

Ответ на вопрос 2:

Когда compat_ioctl осуществляется водителем, то compat_SyS_ioctl называется и не compat_ioctl. Он называется от do_syscall32_irqs_on/do_syscall_32_irqs_off, которые вызывают от entry_INT80_compat. Также sys32_pread/SyS_pread64 вызван от entry_INT80_compat для struct file_operationread обработчик.

+0

'unlocked_ioctl' был создан для совместимости драйверов ядра, I.e. чтобы не нарушать водолазов, которые не поддерживали повторный вход. Я не считаю, что пользователям необходимо знать, что используется. – TrentP

ответ

3

Из разных значений указателя в результатах strace я вижу, что тот, который работает, является 64-разрядной программой, а тот, который дает ENOTTY, представляет собой 32-разрядную программу.

Вам необходимо определить compat_ioctl, чтобы драйвер поддерживал 32-разрядные программы.

+0

Но как вывести те же значения аргументов в ioctl? Как мы можем видеть, правильные значения были переданы, что на самом деле происходит здесь? – 4pie0

+0

Если это помогает, вы можете себе представить, что 'ioctl' действительно 2 разных системных вызовов. Когда 32-разрядный процесс вызывает 'ioctl' в 64-битном ядре, он действительно вызывает' compat_ioctl'. Он должен быть отдельно реализован в каждом драйвере из-за общего характера аргумента 'void *'. Ядро не может перевести значение из 32-битного формата пользовательского пространства в соответствующий 64-разрядный формат для драйвера, потому что он не знает, является ли он указателем на 'int',' short', 'char []'. .. Только водитель знает. Другие системные вызовы не имеют этой проблемы (например, 'read' использует' void * ', но всегда указывает на непрозрачный массив байтов). –

+0

compat_ioctl вызывается из sys_ioctl, не так ли? Проблема заключается в отсутствии вызова sys_ioctl, видимого в ядре, если compat_ioctl не включен (у меня есть точка останова при наборе sys_ioctl). Итак, что называется в этом случае? – 4pie0

 Смежные вопросы

  • Нет связанных вопросов^_^