Может ли kmalloc() вернуть неверную память?
Я пишу модуль ядра Linux, в котором я реализовал связанный список. Я знаю, что в ядре Linux есть список API, но когда я его реализовал, я не знал, поэтому реализовал его, обрабатывая необработанный указатель с помощью kmalloc(). После нескольких часов работы происходит сбой ядра, и в журнале сбоев отображается "Общая ошибка защиты". Журнал также показывает, что это происходит от моей функции поиска связанного списка. Видимо функция поиска похожа на приведенную ниже, которая не имеет логической ошибки.
/*
* Searches in a certain index of hash table for a data
* returns NULL if not found else returns pointer of that element in the table
*/
struct queue_data * search_table(unsigned int hash_index, struct queue_data *new_data)
{
/* Taking a new queue pointer. Which will be pointing to the queue represented
* by new_data at last. */
struct queue_data *ret;
/* First initializing it with first queue on the list */
ret = table[hash_index].next;
/* Iterating through the list to find the desired queue */
while(ret != NULL) {
/* Checking if current queue matches our criteria */
if(ret->saddr == new_data->saddr &&
ret->daddr == new_data->daddr &&
ret->dest == new_data->dest &&
ret->ssrc == new_data->ssrc) {
/* It matched. So I can return it */
return ret;
}
/* It didn't match so I need to go to next queue */
ret = ret->next;
}
/* No queue matched out criteria. Because if it matched it would have not
* come this far. It would have returned before.
* So I need to return a NULL. Now value of 'ret' is NULL.
* I can return 'ret'
*/
return ret;
}
Также очевидно, что функция вставки также безупречна с логической точки зрения. Как обычно, общая ошибка защиты возникает, когда происходит недопустимый доступ к памяти, и я никогда не использовал память, выделенную другим kmalloc()
, Теперь мой вопрос: если я использую память, выделенную kmalloc, есть ли возможность использовать недопустимую память, которую я должен проверить перед использованием?
Фракция аварии журнала здесь:
[ffff8804130cb690] general_protection at ffffffff81661c85
[exception RIP: search_table+52]
RIP: ffffffffa00bc854 RSP: ffff8804130cb748 RFLAGS: 00010286
RAX: d6d4575455d55555 RBX: ffff88040f46db00 RCX: 0000000000000018
RDX: 02b53202ab706c17 RSI: ffff8803fccaaa00 RDI: 00000000000c2568
RBP: ffff8804130cb748 R8: ffffffff8180cb80 R9: 000000000000016d
R10: a3d70a3d70a3d70b R11: ffff8803fccaab58 R12: ffffc9001262cc38
R13: 000000000000079f R14: ffff8803fccaaa00 R15: ffffffffa00cbee8
ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018
При вставке я проверил выделенную память kmalloc следующим образом:
/* Allocating and initializing a new queue.
* If a queue corresponding to it already exists then it's data will
* copied and this queue will be dropped.
* Else this queue will be inserted to the hash table that manages the queues.
*/
new_data = (struct queue_data *)kmalloc(sizeof(struct queue_data), GFP_ATOMIC);
if (!new_data) {
//printk(KERN_ALERT "pkt_queue EXCEPTION: new_data\n");
return NULL;
}
1 ответ
Глядя на код, который вы разместили, единственный возможный источник общего сбоя защиты, который я вижу, это строка:
ret = table[hash_index].next;
Вы не проверяете размер table
так что, возможно, вы получаете доступ к памяти за пределами? Невозможно быть уверенным, не зная как, где и что table
и как вы его инициализируете.
Посмотрев на ваш комментарий, сказав hash_index
, unsigned int
, является результатом модуля HASH_PRIME
макрос, может случиться так, что в какой-то момент вы столкнетесь с возможными проблемами со знаком без знака, так что, несмотря на модуль на HASH_PRIME
Вы фактически выходите за пределы. Возможно добавить:
if (hash_index >= HASH_PRIME) hash_index = HASH_PRIME-1;//or error
Просто ради полноты: как я указывал в комментариях, все функции, которые вы используете, используют ядро u32
тип. Оказывается, именно поэтому ваш код все еще обращался к неправильной памяти. (Напечатал это обновление на телефоне... Ненавижу)