Ядро предоставляет две функции для выполнения необходимых проверок при копировании данных в пространство пользователя и из него. Следует помнить, что ядро никогда не должно слепо следовать за указателем в пространстве пользователя! Одна из этих двух функций должна использоваться всегда.
Для записи в пространство пользователя предоставляется функция copy_to_user()
Для чтения из пространства пользователя используется функция copy_from_user()
copy_to_user(). Эта функция считывает данные, на которые указывает второй параметр, в область памяти, на которую указывает первый параметр, количество данных — третий параметр.Обе эти функции возвращают количество байтов, которые они не смогли скопировать в случае ошибки. При успешном выполнении операции возвращается нуль. В случае такой ошибки стандартным является возвращение системным вызовом значения -EFAULT
Давайте рассмотрим пример системного вызова, который использует функции copy_from_user()
copy_to_user(). Системный вызов silly_copy() является до крайности бесполезным. Он просто копирует данные из своего первого параметра во второй. Это очень не эффективно, так как используется дополнительное промежуточное копирование в пространство ядра безо всякой причины. Но зато это позволяет проиллюстрировать суть дела./*
* Системный вызов silly copy — крайне бесполезная функция,
* которая копирует len байтов из области памяти,
* на которую указывает параметр src, в область памяти,
* на которую указывает параметр dst, с использованием ядра
* безо всякой на то причины. Но это хороший пример!
*/
asmlinkage long sys_silly_copy(unsigned long *src,
unsigned long *dst, unsigned long len) {
unsigned long buf;
/* возвращаем ошибку, если размер машинного слова в ядре
не совпадает с размером данных, переданных пользователем */
if (len != sizeof(buf))
return -EINVAL;
/* копируем из src, который является адресом в пространстве
пользователя, в buf */
if (copy_from_user(&buf, src, len))
return -EFAULT;
/* копируем из buf в dst, который тоже является адресом
в пространстве пользователя */
if (copy_to_user(dst, &buf, len))
return -EFAULT;
/* возвращаем количество скопированных данных */
return len;
}
Следует заметить, что обе функции, copy_from_user()
copy_to_user(), могут блокироваться. Это возникает, например, если страница памяти, содержащая данные пользователя, не находится в физической памяти, а в данный момент вытеснена на диск. В таком случае процесс будет находиться в приостановленном состоянии до тек пор, пока обработчик прерываний из-за отсутствия страниц (page fault handler) не возвратит страницу памяти в оперативную память из файла подкачки на диске.Последняя проверка — это проверка на соответствие правам доступа. В старых версиях ядра Linux стандартом было использование функции suser()
capable() с допустимым значением флага, определяющего тип прав, возвращает ненулевое значение, если пользователь обладает указанным правом, и нуль— в противном случае. Например, вызов capable (CAP_SYS_NICE) проверяет, имеет ли вызывающий процесс возможность модифицировать значение параметра