Как copy_from_user из ядра Linux работает внутри? - PullRequest
13 голосов
/ 25 ноября 2011

Как именно функция copy_from_user() работает внутри?Использует ли он какие-либо буферы или выполняется какое-либо сопоставление памяти, учитывая тот факт, что ядро ​​имеет право доступа к области памяти пользователя?

Ответы [ 4 ]

20 голосов
/ 25 ноября 2011

Реализация copy_from_user() в значительной степени зависит от архитектуры.

В x86 и x86-64 она просто выполняет прямое чтение из адреса пользовательского пространства и запись в адрес пространства ядра, временно отключая SMAP(Предотвращение доступа в режиме супервизора), если оно настроено.Сложность в том, что код copy_from_user() помещен в специальную область, чтобы обработчик ошибок страницы мог распознать, когда в ней происходит ошибка.Ошибка защиты памяти, возникающая в copy_from_user(), не убивает процесс, как если бы он был вызван каким-либо другим кодом контекста процесса, или не вызывает панику ядра, как если бы это произошло в контексте прерывания, - он просто возобновляет выполнение впуть к коду, который возвращает -EFAULT вызывающей стороне.

8 голосов
/ 22 января 2012

относительно того, "как насчет copy_to_user, поскольку ядро ​​передает адрес пространства ядра, как может процесс пользовательского пространства получить к нему доступ"

Процесс пространства пользователя может пытаться получить доступ к любому адресу. Однако, если адрес не отображается в пользовательском пространстве этого процесса (то есть в таблицах страниц этого процесса) или если существует проблема с доступом, например попытка записи в местоположение только для чтения, то генерируется ошибка страницы. Обратите внимание, что, по крайней мере, на x86, каждый процесс имеет все пространство ядра, отображаемое в младшем 1 гигабайте виртуального адресного пространства этого процесса, в то время как 3 верхних гигабайта в общем адресном пространстве 4 ГБ (я использую здесь 32-битную классическую case) используются для текста процесса (т.е. кода) и данных. Копирование в или из пользовательского пространства выполняется кодом ядра, который выполняется от имени процесса, и фактически это отображение памяти (то есть таблицы страниц) этого процесса, которые используются во время копирования. Это происходит во время выполнения в режиме ядра - то есть в привилегированном режиме / режиме супервизора на языке x86. Предполагая, что код пользовательского пространства прошел законное целевое местоположение (то есть адрес, правильно сопоставленный в адресном пространстве этого процесса) для копирования данных, copy_to_user, запуск из контекста ядра сможет нормально записывать этот адрес / область без проблемы и после того, как элемент управления возвращается к пользователю, пользовательское пространство также может считывать данные из этой настройки местоположения самим процессом, с которого можно начать. Более интересные подробности можно найти в главах 9 и 10 «Понимание ядра Linux», 3-е издание, Даниэль П. Бове, Марко Чезати. В частности, access_ok () является необходимой, но не достаточной проверкой достоверности. Пользователь по-прежнему может передавать адреса, не принадлежащие адресному пространству процесса. В этом случае возникнет исключение Page Fault, пока код ядра выполняет копию. Наиболее интересной частью является то, как обработчик ошибок страницы ядра определяет, что ошибка страницы в таком случае не из-за ошибки в коде ядра, а скорее из-за неправильного адреса пользователя (особенно, если рассматриваемый код ядра взят из модуля ядра). загружен).

1 голос
/ 08 апреля 2012

В лучшем ответе что-то не так, copy_ (от | до) пользователь не может использоваться в контексте прерывания, он может спать, копировать (от | до) функция пользователя может быть толькоиспользуемая в контексте процесса, таблица страниц процесса включает в себя всю информацию, которая необходима ядру для доступа к нему, поэтому ядро ​​может получить прямой доступ к адресу пространства пользователя, если мы можем убедиться, что адресуемая страница находится в памяти, используйте копию (от |) Функция _user, потому что они могут проверить это для нас, и если страница с адресом пользовательского пространства не является резидентной, она исправит это для нас напрямую.

0 голосов
/ 25 ноября 2011

Реализация системного вызова copy_from_user() выполняется с использованием двух буферов из разных адресных пространств:

  • буфер пространства пользователя в виртуальном адресном пространстве пользователя.
  • буфер пространства ядра в виртуальном адресном пространстве ядра.

Когда вызывается системный вызов copy_from_user(), данные копируются из буфера пользователя в буфер ядра.

Часть (операция записи) кода драйвера символьного устройства, где используется copy_from_user(), приведена ниже:

ssize_t cdev_fops_write(struct file *flip, const char __user *ubuf,
                        size_t count, loff_t *f_pos) 
{     
    unsigned int *kbuf;
    copy_from_user(kbuf, ubuf, count);
    printk(KERN_INFO "Data: %d",*kbuf); 
}
...