#c #linux-kernel #linux-device-driver
Вопрос:
В настоящее время я провожу эксперименты с модулем ядра.
Я написал функцию, которая принимает указатель на структуру (в пространстве пользователя) в качестве параметра, с целью скопировать эту структуру из пространства пользователя в пространство ядра; следовательно, мне нужно copy_from_user
или __get_user
.
Определение структуры довольно простое:
struct A {
int a;
};
Функция в моем модуле ядра направлена на получение значения a и возврат его значения, которое выглядит следующим образом (с двумя подходами):
static int foo(struct A __user *arg)
{
int num, ret;
if (!access_ok(VERIFY_WRITE, arg, sizeof(struct A)))
return -EFAULT;
/* approach1: directly copy the value from user space */
ret = __get_user(num, (int __user *)amp;arg->a);
if (ret) return -ENOMEM;
/* approach2: allocate space for struct A, then copy the whole struct */
struct A *tmp = kmalloc(sizeof(struct A), GFP_KERNEL);
if (!tmp) return -ENOMEM;
ret = copy_from_user(tmp, (const void __user *)arg, sizeof(struct A));
if (ret) return -EFAULT;
num = tmp->a;
kfree(tmp);
return num;
}
Независимо от того, какой подход я использую, эта функция отлично работает ioctl
. Ниже приведен фрагмент кода в ioctl
:
long foo_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct A __user *tmp_struct;
int ret;
...
switch (cmd) {
case IOC_FOO:
ret = foo((struct A __user *)arg);
break;
...
}
...
return ret;
}
Однако, когда я перейду foo()
к другой функции foo2()
, она выйдет из строя в любом __get_user()
или copy_from_user()
. Псевдокод выглядит следующим образом:
int foo2()
{
int val;
...
struct A __user *addr = the address of struct A in user space
val = foo(addr); /* this is where error occurrs */
...
}
Обратите внимание, что код является более простой версией моего эксперимента. foo2()
вызывается через другой cmd in ioctl()
, выданный тем же процессом. Я получил адрес структуры A — addr
из пользовательского пространства, используя другой ioctl() cmd, который не имеет отношения к этому вопросу. Я уже проверил, что адрес структуры A в пользовательском пространстве правильный (путем печати адресов как в пользовательском пространстве, так и в пространстве ядра), что приводит меня в замешательство — почему действительный адрес пользовательского пространства приведет к ошибке в copy_from_user()
или __get_user()
?
Почему foo()
работает, ioctl()
но не работает foo2()
?
Любая идея будет оценена по достоинству.
Комментарии:
1. Откуда
foo2
звонят? Вы уверены, что это системный вызов, выполненный тем же процессом?2. @NateEldredge:
foo2
вызывается из другого командногоioctl
пункта , выданного тем же процессом.3. @EthanL. можете ли вы показать, как
foo2()
это называлось ?4. @Khaled:
foo2()
был вызван ioctl, который запускает поток ядра. Внутри потока он сначала получает адресstruct A
в пользовательском пространстве, а затем пытается скопировать всю структуру с помощьюcopy_from_user()
. Я проверил, что адресstruct A
в пользовательском пространстве, передаваемый ядру, правильный. Я знаю, что то, что я сделал, может не иметь никакого смысла, как я уже упоминал, я просто играю с простым модулем и провожу с ним некоторые небольшие эксперименты. Вот почему я также хотел бы протестировать интерфейс kthread, так как я никогда раньше не пытался создать поток ядра.
Ответ №1:
«который запускает поток ядра. Внутри темы» ой, это твоя ошибка. Вы можете вызвать копирование от/к пользователю только из потока, который выдал системный вызов или ошибку или иным образом попал в пространство ядра из пользовательского пространства. В некотором смысле, это тот же поток пользовательского пространства, только в пространстве ядра, поэтому вызовы работают. Из нового потока ядра вы больше не находитесь в этом потоке и не связаны с этим конкретным процессом пользовательского пространства, поэтому он не знает.
Тебе повезло, что это не удалось. В некоторых случаях это могло быть связано с init и стереть память init, что привело к панике.