LINUX.ORG.RU

синхронизация функций в загружаемом модуле ядра


0

1

Добрый День.

У меня в загружаемом модуле ядра, происходит подмена одного системного вызова на другой(через таблицу системных вызовов). При закрытии модуля, я возвращаю адреса как и было вначале. Проблем в том, что если я начну обратно менять адреса, а в это время будет выполняться тот самый вызов, то будет ошибка. Как я понимаю мне надо использовать семафор, ожидающий, когда завершится системный вызов, и после уже разрешающий поменять адреса в таблице обратно. Но как я понял семафоры в ядре работают по другому. Вот пример моего кода. Пожалуйста, помогите исправить вылет при выгрузке модуля. Ядро 2.6.

Мне надо дождаться завершения new_sys_write и уже потом менять адреса в interceptor_end() вот тут: (sys_call_table[__NR_write] = (unsigned long *)ref_sys_write;)

код:

unsigned long **sys_call_table;

asmlinkage long (*ref_sys_write)(unsigned int fd, const char __user *buf, size_t count);

asmlinkage long new_sys_write(unsigned int fd, const char __user *buf, size_t count)

{

// тут я вызываю настоящий вызов, чтобы после проанализировать его результат.

long k = ref_sys_write(fd, buf, count);

MyAnalyzeFunc(k, count);

return k;

}

static int __init interceptor_start(void)

{

disable_page_protection();

ref_sys_write = (void *)sys_call_table[__NR_write];

sys_call_table[__NR_write] = (unsigned long *)new_sys_write;

enable_page_protection();

return 0;

}

static void __exit interceptor_end(void)

{

if(!sys_call_table) return;

disable_page_protection();

sys_call_table[__NR_write] = (unsigned long *)ref_sys_write;

enable_page_protection();

}

module_init(interceptor_start);

module_exit(interceptor_end);


Ответ на: комментарий от metawishmaster

Имеется в виду wait_event_interruptible(wq, condition) ? А как его конкретно применить ? По этому методу информации почти никакой. Какого типа очередь и как её объявить/добавить в неё объект?

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

Попробовал, в этот раз терминал не упал. Вывело сообщение «Убито», но терминал не заблокировался. Однако модуль так и не выгрузился. Я сделал так:

unsigned long **sys_call_table;

static DECLARE_WAIT_QUEUE_HEAD(wq);

static int flag = 0;

asmlinkage long (*ref_sys_write)(unsigned int fd, const char __user *buf, size_t count);

asmlinkage long new_sys_write(unsigned int fd, const char __user *buf, size_t count)

{

// тут я вызываю настоящий вызов, чтобы после проанализировать его результат.

long k = ref_sys_write(fd, buf, count);

MyAnalyzeFunc(k, count);

// Добавление

flag = 1;

wake_up_interruptible(&wq);

// Добавление окончено

return k;

}

static int __init interceptor_start(void)

{

disable_page_protection();

ref_sys_write = (void *)sys_call_table[__NR_write];

sys_call_table[__NR_write] = (unsigned long *)new_sys_write;

enable_page_protection();

return 0;

}

static void __exit interceptor_end(void)

{

if(!sys_call_table) return;

disable_page_protection();

// Добавление

flag = 0;

wait_event_interruptible(wq, flag != 0);

flag = 0;

// Добавление окончено

sys_call_table[__NR_write] = (unsigned long *)ref_sys_write;

enable_page_protection();

}

module_init(interceptor_start);

module_exit(interceptor_end);

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

Если не поставить перед wait_event_interruptible(wq, flag != 0); То в итоге условие будет сразу снято, т.к. в системе постоянно происходит куча процессов write и они поставят flag=1 и разбудят условие. Тогда когда я захочу выгрузить модуль, он выгрузится сразу, даже если выполняется write.

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

а если убрать второй flag = 0; (который после wait_event_interruptible(wq, flag != 0);) то систему выкинет в чёрный экран. Можно перейти в Альт-ф2 или Альт-ф1.

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

И разве произойдёт wait_event_interrutible(wq, flag != 0); в цикле? Мы ведь flag = 1 нигде не делаем

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

Вот так, я после rmmod кручусь в бесконечном цикле в терминале и ничего не могу сделать. Т.к. флаг никогда не станет 1

asmlinkage long new_sys_write(unsigned int fd, const char __user *buf, size_t count)

{

// тут я вызываю настоящий вызов, чтобы после проанализировать его результат.

long k = ref_sys_write(fd, buf, count);

flag = 0;

MyAnalyzeFunc(k, count);

wake_up_interruptible(&wq);

// Добавление окончено

return k;

}

static void __exit interceptor_end(void)

{

if(!sys_call_table) return;

disable_page_protection();

// Добавление

do

wait_event_interruptible(wq, flag != 0);

while(flag != 1)

// Добавление окончено

sys_call_table[__NR_write] = (unsigned long *)ref_sys_write;

enable_page_protection();

}

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

сорри, отходил... да, то (do-while) был небольшой бред %)

DECLARE_WAIT_QUEUE_HEAD(wq);
static int finished;

unsigned long **sys_call_table;
while (finished != 1)
asmlinkage long (*ref_sys_write) (unsigned int fd, const char __user * buf, size_t count);

asmlinkage long new_sys_write(unsigned int fd, const char __user * buf, size_t count)
{
        finished = 0;
// тут я вызываю настоящий вызов, чтобы после проанализировать его результат.

        long k = ref_sys_write(fd, buf, count);

        MyAnalyzeFunc(k, count);

        finished = 1;
        wake_up_interruptible(&wq);

        return k;

}

static int __init interceptor_start(void)
{

        disable_page_protection();

        ref_sys_write = (void *)sys_call_table[__NR_write];

        sys_call_table[__NR_write] = (unsigned long *)new_sys_write;

        enable_page_protection();


        return 0;

}

static void __exit interceptor_end(void)
{

        if (!sys_call_table)
                return;

        wait_event_interrutible(wq, finished != 0);

        disable_page_protection();

        sys_call_table[__NR_write] = (unsigned long *)ref_sys_write;

        enable_page_protection();

}

module_init(interceptor_start);

module_exit(interceptor_end);
«flag = 1» нужно перед wake_up_interruptible

metawishmaster ★★★★★
()
Последнее исправление: metawishmaster (всего исправлений: 1)
Ответ на: комментарий от metawishmaster

while (finished != 1) asmlinkage long (*ref_sys_write) (unsigned int fd, const char __user * buf, size_t count);

while (finished != 1) - перед ref_sys_write это ошибка или так и должно быть?)

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

в системе много вызовов write происходит, поэтому я думаю flag всегда будет установлен в 1, и при выгрузке модуля мы сразу начнём выгружаться, не смотря на то, что ещё выполняется какой-либо write. поэтому я думаю терминал подвисает.

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

В первый раз я finished = 0; поставил после long k = ref_sys_write(fd, buf, count); тогда терминал подвис. Когда я поставил так :

finished = 0;

long k = ref_sys_write(fd, buf, count);

то терминал не подвис, было написано «Убито» и выданы сообщения от ядра. После этого я снова могу пользоваться терминалом, однако модуль так и не выгрузился.

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

сделал, в этот раз я вылетел в чёрный экран(графическая оболочка упала?) , перешёл там в Альт-ф2 и в dmesg просмотрел, увидел запись wait_event_interruptible

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

в данный момент я убрал MyAnalyzeFunc и делаю там просто printk(«my message\n»);

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

Если можете, скиньте мыло или аську, я туда отправлю полный код, если Вам захочется на своей машине потестить или для удобства. моё мыло livko25@mail.ru можете отправить контакты туда.

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

в данный момент у меня происходит следующее: после rmmod выдаются собщения от ядра в терминал и далее я вновь получаю контроль над терминалом. Однако модуль не выгружен(проверил через lsmod) и также не загружается/ не выгружается. Но сообщение выдаёт.

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