2017-02-16 4 views
2

Ich habe Kernel-Modul (4.4.32 Kernel), die ioctl Aufruf implementiert durch Zuweisen von ioctl Handler struct file_operationsunlocked_ioctl Zeiger. Alles funktioniert gut, aber ich bekam Programm (binary only), kompiliert für 2.6 oder vielleicht 2.4 kernel, was nicht dazu führt, dass kernel einen Aufruf von ioctl für mein Modul registriert, wenn ich dieses Programm auf meinem 4.4.32 starte. Da dieses Programm auf älteren Kernel kompiliert wurde, verwendet es ältere ioctl Schnittstelle, d. H. ioctl Zeiger in file_operations Struktur, nicht unlocked_ioctl.Warum wird der ioctl-Aufruf nicht an sys_ioctl übergeben?

Das ältere Programm erstellt eine Konsole für visuelle Interaktion mit Benutzer und muss als root von der Stammkonsole ausgeführt werden.

Ich habe strace auf dieses Programm und überprüft, dass das Programm ENOTTY für 2. ioctl empfängt, also habe ich Testprogramm geschrieben, das gleiche ioctl Aufrufe an das Kernelmodul macht, das Fehlerprogramm tut.

Ich habe verifiziert, dass die von strace aufgezeichnete Ablaufverfolgung für beide Programme für diese ioctl dieselbe ist, d. H. Mit denselben Argumenten in derselben Reihenfolge aufgerufen wird.

Der relevante Teil meines Testprogramm ist:

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

Die straces:

Mein Testprogramm:

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 +++ 

Fehlerprogramm:

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 

Wie Sie kann sehen, in beiden Fällen die entsprechenden ioctl Anrufe sind gleich, dh:

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:

Was kann der Grund sein, dass der zweite Aufruf von ioctl (das mit cmd 0x70c0) den Kernel nicht sys_ioctl/vfs_ioctl Funktionen bekommt aufgerufen, wenn es vom (alten) Fehlerprogramm ausgeführt wird (Ich habe einen Breakpoint auf den laufenden Kernel gesetzt - der Aufruf wird vom Kernel nicht aufgezeichnet, obwohl der Aufruf des ersten ioctl korrekt aufgezeichnet wurde und der Breakpoint für beide Programme erreicht wird)?

Frage 2:

Wo der Haltepunkt einzufügen, dies zu debuggen? Warum sehe ich sys_ioctl im Fehlerfall überhaupt nicht?


EDIT:

Dank Wumpus Q. Wumbley für die Antwort auf Frage 1.

Antwort auf Frage 2 ist:

Wenn compat_ioctl durch den Fahrer durchgeführt wird, dann wird die compat_SyS_ioctl und nicht compat_ioctl genannt. Es heißt von do_syscall32_irqs_on/, die von entry_INT80_compat aufgerufen werden. Auch sys32_pread/SyS_pread64 wird von entry_INT80_compat für struct file_operation 's read Handler aufgerufen.

+0

'entriegelt_ioctl' wurde für die Kernel-Treiber-Kompatibilität erstellt, d.i. um zu vermeiden, Taucher zu brechen, die kein Wiedereintritt ioctl unterstützt haben. Ich glaube nicht, dass Userspace wissen muss, welches verwendet wird. – TrentP

Antwort

3

Aus den verschiedenen Zeigerwerten in den strace Ergebnissen kann ich sehen, dass das, das funktioniert, ein 64-Bit-Programm ist und das, das ENOTTY gibt, ist ein 32-Bit-Programm.

Sie müssen einen compat_ioctl definieren, damit Ihr Treiber 32-Bit-Programme unterstützt.

+0

Aber wie die gleichen Werte von Argumenten zu ioctl zu erklären? Wie können wir sehen, dass die richtigen Werte bestanden wurden, was hier wirklich fehlschlägt? – 4pie0

+0

Wenn es hilft, können Sie sich vorstellen, dass "ioctl" wirklich 2 verschiedene syscalls ist. Wenn ein 32-Bit-Prozess auf einem 64-Bit-Kernel "ioctl" aufruft, ruft er "compat_ioctl" auf. Wegen der allgemeinen Natur des Arguments "void *" muss es in jedem Treiber separat implementiert werden. Der Kernel kann den Wert aus dem 32-Bit-Userspace-Format nicht in ein entsprechendes 64-Bit-Format für den Treiber übersetzen, weil er nicht weiß, ob es ein Zeiger auf 'int',' short', 'char []' ist. .. Nur der Fahrer weiß es. Andere Syscalls haben dieses Problem nicht (z.B. verwendet 'read' ein' void * ', aber es zeigt immer auf ein undurchsichtiges Byte-Array). –

+0

compat_ioctl wird von sys_ioctl aufgerufen, oder? Das Problem ist, dass kein Aufruf von sys_ioctl im Kernel sichtbar ist, wenn compat_ioctl nicht aktiviert ist (ich habe einen Haltepunkt auf sys_ioctl gesetzt). Was heißt in diesem Fall? – 4pie0

Verwandte Themen