Принудительное завершение copy_to_user () - PullRequest
0 голосов
/ 02 мая 2018

Я пытаюсь написать тест, в котором copy_to_user () завершается ошибкой (копирует только некоторые данные или вообще не копирует их без использования указателей NULL), но безуспешно.

В тесте в пользовательском режиме есть строки:

type to[1];
foo(to);

foo - это функция-обертка, которая вызывает системный вызов со строками:

type from[2] = {something1, something2};
int not_copied = copy_to_user(to, from, sizeof(type) * 2);

Оказывается, not_copied равен 0, даже когда я пытаюсь использовать malloc для объявления "type to". Также «to [0]» и «to [1]» - это «что-то1» и «что-то2» соответственно.

Правильно ли я считаю, что мое объявление 'type to' не ограничивает память назначения copy_to_user как положено?

А как мне сделать так, чтобы он не работал?

спасибо.

Ответы [ 2 ]

0 голосов
/ 04 мая 2018

Мне удалось сделать надежный сбой, внеся следующие изменения:

type to[SMALL_INTEGER]
foo(to)

упаковщик имеет:

type from[HUGE_INTEGER]
// fill from with huge amount of data <- unsure if this part is necessary
int not_copied = copy_to_user(to, from, sizeof(type) * HUGE_INTEGER);
0 голосов
/ 02 мая 2018

Насколько я понимаю, для того, чтобы copy_to_user потерпел неудачу, некоторые адреса в пределах диапазона должны быть не записанными или не отображенными. Ваш type to[1] - это просто адрес где-то на странице памяти пользовательского пространства; если он находится в стеке, адрес сразу после конца всегда будет доступен для записи, потому что стек уменьшается (если вы не используете HPPA, чего вы почти наверняка нет); если вы поместите его в сегмент данных, вам нужно будет очень тщательно все настроить, чтобы убедиться, что он был в самом конце сегмента данных, и сразу после этого ничего не было; в принципе malloc выделение может не иметь ничего сразу после этого, но если вы не используете распределитель, такой как ElectricFence, который преднамеренно помещает не отображенные защитные страницы сразу после каждого выделения, он почти наверняка не будет.

Чтобы преднамеренно настроить ситуацию, когда запись обращается как к доступной, так и к недоступной памяти, вы можете сделать что-то вроде этого:

size_t pagesize = sysconf(_SC_PAGESIZE);
char *to_allocation = mmap(0, 2*pagesize, PROT_READ|PROT_WRITE,
                           MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
memset(to_allocation, 0x55, 2*pagesize); // force allocation
mprotect(to_allocation + pagesize, pagesize, PROT_NONE);

foo(to_allocation + pagesize - sizeof(type));

(Но с обработкой ошибок, конечно.)

...