"do_fork()" не линкуется к модулю (WARNING: "do_fork" [`/my_mod.ko] undefined!)

Модератор: Модераторы разделов

Аватара пользователя
RasenHerz
Сообщения: 1341
ОС: Arch Linux amd64

"do_fork()" не линкуется к модулю

Сообщение RasenHerz »

решил написать модуль, который мог бы создавать процессы уровня пользоватея и сразу столкнулся с такой проблемой:
при компилировании gcc выдает WARNING: "do_fork" [`/my_mod.ko] undefined!
а при попытке загрузить модуль dmesg возвращает: insmod: error inserting 'my_mod.ko': -1 Unknown symbol in module

вот собственно код:

Код:

#include <asm/thread_info.h> #include <linux/sched.h> #include <linux/kthread.h> #define STACKSIZE 4096 typedef void (*CH_CALL)(void*); typedef void** CH_STACK; typedef void* CH_DATA; pid_t my_mod_create_child(CH_CALL, CH_DATA, int); int my_mod_child_fn(CH_DATA); int init_module(){ pid_t child = my_mod_create_child((CH_CALL)&my_mod_child_fn, "Hello World!\n", STACKSIZE); printk("<1>RasenHerz: Child PID is %i\n", (int)child); return 0; } void cleanup_module(void){ printk("<1>RasenHerz: Module unloaded.\n"); } int my_mod_child_fn(CH_DATA data){ printk("<1>RasenHerz: %s", (char*)data); } pid_t my_mod_create_child(CH_CALL call_adr, CH_DATA data, int stack_size) { struct pt_regs regs = { .ebx = (unsigned long)call_adr, .edx = (unsigned long)data, .xds = __USER_DS, .xes = __USER_DS, .xfs = __USER_DS, .orig_eax = -1, .xcs = __USER_CS, .eflags = X86_EFLAGS_IF|X86_EFLAGS_SF|X86_EFLAGS_PF|0x2 }; return (pid_t)(do_fork(SIGCHLD, 0, &regs, 0, NULL, NULL)); } MODULE_LICENSE("GPL");

все заголовочные файлы присоеденены, код не содерхит явных ошибок. вот тока почему не прилинкована do_fork()?
Спасибо сказали:
int_0dh
Сообщения: 20
ОС: Linux

Re: "do_fork()" не линкуется к модулю

Сообщение int_0dh »

>>решил написать модуль, который мог бы создавать процессы уровня пользоватея и сразу столкнулся с такой проблемой:
>>при компилировании gcc выдает WARNING: "do_fork" [`/my_mod.ko] undefined!
>>а при попытке загрузить модуль dmesg возвращает: insmod: error inserting 'my_mod.ko': -1 Unknown symbol in module
>>
>>вот собственно код:

1. Используйте call_usermodehelper() для этого
2 Код Ваш страшный и неправильный
Спасибо сказали:
Аватара пользователя
serzh-z
Бывший модератор
Сообщения: 8259
Статус: Маньяк
ОС: Arch, Fedora, Ubuntu

Re: "do_fork()" не линкуется к модулю

Сообщение serzh-z »

RasenHerz писал(а):
03.04.2008 09:23
вот тока почему не прилинкована do_fork()?
Потому что do_fork() не экспортируется ядром.

P.S.: просьба избавиться от рисунка в подписи.
Спасибо сказали:
Аватара пользователя
RasenHerz
Сообщения: 1341
ОС: Arch Linux amd64

Re: "do_fork()" не линкуется к модулю

Сообщение RasenHerz »

Потому что do_fork() не экспортируется ядром
.
неужели нет другого способа создать процесс пользовательского уровня в ядре? раньше я линковал do_fork() считав соответствующий адрес. вот код:

Код: Выделить всё

int my_mod_child_fn(CH_DATA data){
  printk("<1>RasenHerz: %s", (char*)data);
  return 0;
 }

typedef long (*do_fork_t)(unsigned long clone_flags,
              unsigned long stack_start,
              struct pt_regs *regs,
              unsigned long stack_size,
              int __user *parent_tidptr,
              int __user *child_tidptr);


pid_t my_mod_create_child(CH_CALL call_adr, CH_DATA data, int stack_size)
 {
    do_fork_t fork_func = (do_fork_t)0xc0120ce9UL; /* адрес я взял из /proc/kallsyms */
    struct pt_regs regs = {
        .rbx = (unsigned long)call_adr,
        .rdx = (unsigned long)data,

        .orig_rax = -1,

        .cs = __USER_CS,
        .eflags = X86_EFLAGS_IF|X86_EFLAGS_SF|X86_EFLAGS_PF|0x2
    };
    return (pid_t)(fork_func(SIGCHLD, 0, &regs, 0, NULL, NULL));
}

MODULE_LICENSE("GPL");

код работоспособен, но модуль валится при возвращении значения из функции my_mod_child_fn.
P.S.: просьба избавиться от рисунка в подписи.

почему? у меня это стандартный юзербар на всех форумах...
1. Используйте call_usermodehelper() для этого

ладно, попробую.
2 Код Ваш страшный и неправильный

так покажи КРАСИВЫЙ и ПРАВИЛЬНЫЙ.
Спасибо сказали:
int_0dh
Сообщения: 20
ОС: Linux

Re: "do_fork()" не линкуется к модулю

Сообщение int_0dh »

RasenHerz писал(а):
03.04.2008 16:56
Потому что do_fork() не экспортируется ядром
.
неужели нет другого способа создать процесс пользовательского уровня в ядре? раньше я линковал do_fork() считав соответствующий адрес. вот код:

Код: Выделить всё

int my_mod_child_fn(CH_DATA data){
  printk("<1>RasenHerz: %s", (char*)data);
  return 0;
 }

typedef long (*do_fork_t)(unsigned long clone_flags,
              unsigned long stack_start,
              struct pt_regs *regs,
              unsigned long stack_size,
              int __user *parent_tidptr,
              int __user *child_tidptr);


pid_t my_mod_create_child(CH_CALL call_adr, CH_DATA data, int stack_size)
 {
    do_fork_t fork_func = (do_fork_t)0xc0120ce9UL; /* адрес я взял из /proc/kallsyms */
    struct pt_regs regs = {
        .rbx = (unsigned long)call_adr,
        .rdx = (unsigned long)data,

        .orig_rax = -1,

        .cs = __USER_CS,
        .eflags = X86_EFLAGS_IF|X86_EFLAGS_SF|X86_EFLAGS_PF|0x2
    };
    return (pid_t)(fork_func(SIGCHLD, 0, &regs, 0, NULL, NULL));
}

MODULE_LICENSE("GPL");

код работоспособен, но модуль валится при возвращении значения из функции my_mod_child_fn.
P.S.: просьба избавиться от рисунка в подписи.

почему? у меня это стандартный юзербар на всех форумах...
1. Используйте call_usermodehelper() для этого

ладно, попробую.
2 Код Ваш страшный и неправильный

так покажи КРАСИВЫЙ и ПРАВИЛЬНЫЙ.



1) Если Вы внимательно посмотрите на do_fork() (kernel/fork.c) , то вы сразу поймете что код не работоспособный впринципе.
Он должен валить процесс в контексте которого было вызвано my_mod_create_chilld() по SIGSEGV. Подозреваю что это insmod

2) Вы похоже не понимаете как работает fork() - советую почитать Баха для начала

3) Мы с Вами на брудершафт вроде не пили (хотя я точно не помню - может и пили, просто я пьян был)
Спасибо сказали:
Аватара пользователя
RasenHerz
Сообщения: 1341
ОС: Arch Linux amd64

Re: "do_fork()" не линкуется к модулю

Сообщение RasenHerz »

do_fork() еще какой работоспособный - надо просто грамотно настроить регистры, к примеру так:

.ebx = (unsigned long)call_adr,
.edx = (unsigned long)data,

.xds = __USER_DS,
.xes = __USER_DS,
.xfs = __KERNEL_PERCPU,

.orig_eax = -1,

.xcs = __KERNEL_CS,
.eip = __KERNEL_TH_H,
.eflags = X86_EFLAGS_IF|X86_EFLAGS_SF|X86_EFLAGS_PF|0x2

и все будет прекрасно работать. я понимаю как работает fork().
советую почитать Баха для начала
спасибо, у меня свои источники знаний =).
я извиняюсь, если мой предыдущий пост имел в какой-то степени оскорбительный характер для вас, int_0dh, но когда люди делают заявления такого типа:
2 Код Ваш страшный и неправильный

они должны чем то подкреплять свои слова, ведь я, к примеру, вопреки вашему заявлению, вполне могу доказать его работоспособность (про "красоту", которая как я понял - стиль кода, я молчу - код писал сразу на форуме, так что здесь не до форматирования и прочего выпендрежа) - а вы только сыпете какими-то нечего не значящими репликами, хотя вполне могли показать что НЕ ТАК, пример что ли оставить. так что моя агрессивная реакция должна была быть для вас вполне ожидаема, так что без обид.
Спасибо сказали:
int_0dh
Сообщения: 20
ОС: Linux

Re: "do_fork()" не линкуется к модулю

Сообщение int_0dh »

Посмотрел на код повнимательнее. Прошу прощения, в принципе новый процесс он создаст - так что беру свои слова обратно.
Однако он все-таки нерабочий - в частности вы неправильно заполняете IP :) Если вы хотите запустить пользовательский
процесс вы должны передать флаг CLONE_VM в do_fork()
Стоит добавить некую функцию-хелпер которая бы дергала основную функцию в новом процессе а потом бы do_exit(0).

В итоге должно получится что-то в роде:

void __proc_start(void)
{
asm("movl %edx, %eax\n"
"pushl %edx\n"
"call %ebx\n" // hehe, we call a __new_proc() routine
"pushl %eax\n" // exit(-1)
"call do_exit\n"::);
}

void start_my_cool_proc(int (*__new_proc)(void *), void *arg)
{
struct pt_regs regs;
memset(&regs, 0, sizeof(regs));

regs.ebx = (unsigned)__new_proc;
rergs.edx = arg;
regs.eax = (unsigned)-1;
regs.xds = regs.xes = regs.xcs = __USER_DS;
regs.eip = __proc_start; /* ВАЖНО!!! Новый процесс начнет выполняться именно отсюда */
regs.eflags = X86_EFLAGS_IF | X86_EFLAGS_SF | X86_EFLAGS_PF ;
return do_fork(SIGCHILD | CLONE_VM, 0, &regs, 0, NULL, NULL);
}

Потом в порожденном процессе нужно сделать execve() для перезаписи образа процесса.
И все-таки я Вас прошу не изобретать велосипедов и использовать стандартные средства - например call_usermodehelper() :)
Спасибо сказали:
Аватара пользователя
RasenHerz
Сообщения: 1341
ОС: Arch Linux amd64

Re: "do_fork()" не линкуется к модулю

Сообщение RasenHerz »

спс! =) на регистр eip у меня с самого начала были подозрения, поэтому нарыл в гугле что в него дожен быть передан некий адрес, который содержит ф-цию запускающую новый процесс, потом нарыл что происходит дальше. в общем, пришлось писать асемблерные вставки =))) потом прочел ваш пост =))) был озадачен =))) - мой и ваш код практически идентичен ) еще раз спасибо
Спасибо сказали:
Аватара пользователя
RasenHerz
Сообщения: 1341
ОС: Arch Linux amd64

Re: "do_fork()" не линкуется к модулю

Сообщение RasenHerz »

int_0dh писал(а):
03.04.2008 19:29
Посмотрел на код повнимательнее. Прошу прощения, в принципе новый процесс он создаст - так что беру свои слова обратно.
Однако он все-таки нерабочий - в частности вы неправильно заполняете IP :)

что-то я вчера на радостях аж забылся ) - eip заполнен правильно, т.к. __KERNEL_TH_H я локально дефайнил как адрес ф-ции kernel_thread_helper, которая в свою очередь, создает поток ядра. правда все равно функциональность несколько не та, что мне надо. =))
Спасибо сказали: