LINUX.ORG.RU

EIP текущего процесса из ядра


0

0

Народ, каким образом из обработчика системного вызова получить значение eip текущего процесса до обращения к обработчику???? я использовал вот такую конструкцию... struct pt_regs *regss=((struct pt_regs*)(THREAD_SIZE + (unsigned long)current->thread_info)) -1; но обращаясь к regss->eip я постоянно тыкуюсь по одному и тому же адресу 0хffffe410... как быть???

anonymous

>но обращаясь к regss->eip я постоянно тыкуюсь по одному и тому же
>адресу 0хffffe410... как быть???

Это и есть та самая точка, из которой происходит вход в ядро.
Т.е. это правильный ответ на поставленный вопрос.

Murr ★★
()
Ответ на: комментарий от Murr

Более-менее поздние ядра Linux экспортируют как DSO точку входа в себя.
Они проецируют на ia32 страницу 0xffffe000 доступную для чтения из userspace и экспортируют с нее символ _kernel_vsyscall - функцию, которая осуществляет вход в ядро. Все что нужно сделать glibc, чтобы войти в ядро - это вызвать эту функцию, что удачно скрывает особенности реализации входа в ядро в коде самого ядра.

Я в свое время пытался писать код, который меняет эту страницу, и позволяет изменить вход и выход в/из ядра для всех процессов (в том числе привилегированных). Подробнее ткни в nickname - там будет список моих тем (что-то вроде RH9/do_brk - как раз про это).

Murr ★★
()
Ответ на: комментарий от Murr

так как мне из этого адреса получить реальный eip процесса до того, как произойдет системный вызов???

anonymous
()
Ответ на: комментарий от Murr

из всего вышеизложенного я понял, что есть фиксированная область памяти ядра, доступная так же пользовательскому процессу (0xffffe000). В этой области находится vsyscall но каким образом обратившись к этой области я могу выудить eip процесса, который вызвал этот самый vsyscall ?

anonymous
()
Ответ на: комментарий от Murr

есть ли возможность вытащить из стека значение eip, если для перехода к такблице vsyscall используется команда call ????

anonymous
()
Ответ на: комментарий от anonymous

>так как мне из этого адреса получить реальный eip процесса до того, как произойдет системный вызов???

Я же написал - это и есть реальный eip.
Тебе backtrace нужен?

Murr ★★
()
Ответ на: комментарий от anonymous

>есть ли возможность вытащить из стека значение eip, если для перехода к такблице vsyscall используется команда call ????

стандартно: нужно раскручивать backtrace. Посмотрите код vsyscall (arch/i386/kernel/vsyscall*), если там используются frame pointers, то нужно снять со стека по адресу [ebp+n] - это и будет точка возврата из __kernel_vsyscall (вероятно, одна из функций glibc).

Murr ★★
()
Ответ на: комментарий от anonymous

eip=ffffe410 esp=bfffebd4 ebp+0=bfffebec ebp+1=bfffebed ebp+2=bfffebee ebp+3=bfffebef ebp+4=bfffebf0 ebp+5=bfffebf1 eip=ffffe410 esp=bffff0e0 ebp+0=bffff0f8 ebp+1=bffff0f9 ebp+2=bffff0fa ebp+3=bffff0fb ebp+4=bffff0fc ebp+5=bffff0fd eip=ffffe410 esp=bfffe764 ebp+0=bfffe77c ebp+1=bfffe77d ebp+2=bfffe77e ebp+3=bfffe77f ebp+4=bfffe780 ebp+5=bfffe781 eip=ffffe410 esp=bfffe5a0 ebp+0=bfffe5b8 ebp+1=bfffe5b9 ebp+2=bfffe5ba ebp+3=bfffe5bb ebp+4=bfffe5bc ebp+5=bfffe5bd eip=ffffe410 esp=bfffe5a0 ebp+0=bfffe5b8 ebp+1=bfffe5b9 ebp+2=bfffe5ba ebp+3=bfffe5bb ebp+4=bfffe5bc ebp+5=bfffe5bd eip=ffffe410 esp=bfffe670 ebp+0=bfffe688 ebp+1=bfffe689 ebp+2=bfffe68a ebp+3=bfffe68b ebp+4=bfffe68c ebp+5=bfffe68d eip=ffffe410 esp=bfffde20 ebp+0=bfffde38 ebp+1=bfffde39 ebp+2=bfffde3a ebp+3=bfffde3b ebp+4=bfffde3c ebp+5=bfffde3d eip=ffffe410 esp=bfffdc60 ebp+0=bfffdc78 ebp+1=bfffdc79 ebp+2=bfffdc7a ebp+3=bfffdc7b ebp+4=bfffdc7c ebp+5=bfffdc7d eip=ffffe410 esp=bfffdef0 ebp+0=bfffdf08 ebp+1=bfffdf09 ebp+2=bfffdf0a ebp+3=bfffdf0b ebp+4=bfffdf0c ebp+5=bfffdf0d eip=ffffe410 esp=bfffd530 ebp+0=bfffd548 ebp+1=bfffd549 ebp+2=bfffd54a ebp+3=bfffd54b ebp+4=bfffd54c ebp+5=bfffd54d eip=ffffe410 esp=bfffd530 ebp+0=bfffd548 ebp+1=bfffd549 ebp+2=bfffd54a ebp+3=bfffd54b ebp+4=bfffd54c ebp+5=bfffd54d eip=ffffe410 esp=bfffd1c0 ebp+0=bfffd1d8 ebp+1=bfffd1d9 ebp+2=bfffd1da ebp+3=bfffd1db ebp+4=bfffd1dc ebp+5=bfffd1dd eip=ffffe410 esp=bfffd1c0 ebp+0=bfffd1d8 ebp+1=bfffd1d9 ebp+2=bfffd1da ebp+3=bfffd1db ebp+4=bfffd1dc ebp+5=bfffd1dd eip=ffffe410 esp=bfffd1c0 ebp+0=bfffd1d8 ebp+1=bfffd1d9 ebp+2=bfffd1da ebp+3=bfffd1db ebp+4=bfffd1dc ebp+5=bfffd1dd eip=ffffe410 esp=bfffda00 ebp+0=bfffda18 ebp+1=bfffda19 ebp+2=bfffda1a ebp+3=bfffda1b ebp+4=bfffda1c ebp+5=bfffda1d eip=ffffe410 esp=bfffde20 ebp+0=bfffde38 ebp+1=bfffde39 ebp+2=bfffde3a ebp+3=bfffde3b ebp+4=bfffde3c ebp+5=bfffde3d eip=ffffe410 esp=bfffdc30 ebp+0=bfffdc48 ebp+1=bfffdc49 ebp+2=bfffdc4a ebp+3=bfffdc4b ebp+4=bfffdc4c ebp+5=bfffdc4d eip=ffffe410 esp=bfffdc30 ebp+0=bfffdc48 ebp+1=bfffdc49 ebp+2=bfffdc4a ebp+3=bfffdc4b ebp+4=bfffdc4c ebp+5=bfffdc4d eip=ffffe410 esp=bfffdc80 ebp+0=bfffdc98 ebp+1=bfffdc99 ebp+2=bfffdc9a ebp+3=bfffdc9b ebp+4=bfffdc9c ebp+5=bfffdc9d eip=ffffe410 esp=bfffd894 ebp+0=bfffd8ac ebp+1=bfffd8ad ebp+2=bfffd8ae ebp+3=bfffd8af ebp+4=bfffd8b0 ebp+5=bfffd8b1 eip=ffffe410 esp=bffff0e0 ebp+0=bffff0f8 ebp+1=bffff0f9 ebp+2=bffff0fa ebp+3=bffff0fb ebp+4=bffff0fc ebp+5=bffff0fd eip=ffffe410 esp=bffff0f0 ebp+0=bffff108 ebp+1=bffff109 ebp+2=bffff10a ebp+3=bffff10b ebp+4=bffff10c ebp+5=bffff10d eip=ffffe410 esp=bfffe7f4 ebp+0=bfffe80c ebp+1=bfffe80d ebp+2=bfffe80e ebp+3=bfffe80f ebp+4=bfffe810 ebp+5=bfffe811

код следующий: printk("eip=%x esp=%x ebp+0=%x ebp+1=%x ebp+2=%x ebp+3=%x ebp+4=%x ebp+5=%x\n",regss->eip,regss->esp,regss->ebp,(unsigned long*)((regss->ebp)+1),(unsigned long*)((regss->ebp)+2),(unsigned long*)((regss->ebp)+3),(unsigned long*)((regss->ebp)+4),(unsigned long*)((regss->ebp)+5));

ничего не понимаю=(((

anonymous
()
Ответ на: комментарий от anonymous

Только что посмотрел код. Там не используются frame pointers.

Значит код возврата - по адресу [esp] (или [esp+2]).
Как посчитать esp - понятно.
Как прочитать по нужному адресу - access_process_vm

Murr ★★
()
Ответ на: комментарий от Murr

struct pt_regs *regss=((struct pt_regs*)(THREAD_SIZE + (unsigned long)current->thread_info)) -1; unsigned long esp = regss->esp;

правильно???

unsigned long ret; int i; i=access_process_vm(current,(unsigned long*)(esp)+2,&ret,sizeof(ret),0);

правильная конструкция для получения значения адреса возврата по адресу [esp+2]

anonymous
()
Ответ на: комментарий от Murr

> Более-менее поздние ядра Linux экспортируют как DSO точку входа в себя.
> Они проецируют на ia32 страницу 0xffffe000 доступную для чтения из
> userspace и экспортируют с нее символ _kernel_vsyscall

Murr, чувствую себя полным занудой, но хочу поправить :)

механизм DSO не используется для экспортирования __kernel_vsyscall. поддержку
linux-gate.so можно убрать, и все будет работать.

__kernel_vsyscall передается libc NEW_AUX_ENT(AT_SYSINFO, __kernel_vsyscall).

а вот зачем вообще нужна эта dll, я не очень понимаю. по моему, она нужна
только для того, чтобы gdb работал, там dwarf в основном и лежит, кода
совсем немного. знать бы еще как этот dwarf устроен...

другое дело, что в будущем возможно будет всунуть туда, например, реализацию
gettimeofday() и она будет работать целиком в user level.

idle ★★★★★
()
Ответ на: комментарий от idle

idle:

>__kernel_vsyscall передается libc NEW_AUX_ENT(AT_SYSINFO, _kernel_vsyscall).

Кошмар какой.

>а вот зачем вообще нужна эта dll

По-моему красивше. :)

Murr ★★
()
Ответ на: комментарий от anonymous

anonymous:

Я не помню точно что, где и как лежит. На первый взгляд только режет глаз (unsigned long*)(esp)+2. Все же ((unsigned long *)esp)+1 или же (unsigned long *)esp.

Murr ★★
()
Ответ на: комментарий от anonymous

struct pt_regs *regss=((struct pt_regs*)(THREAD_SIZE + (unsigned long)current->thread_info)) -1; unsigned long esp = regss->esp;

правильно???

unsigned long ret; int i; i=access_process_vm(current,(unsigned long*)(esp)+2,&ret,sizeof(ret),0);

правильная конструкция для получения значения адреса возврата по адресу [esp+2] ??

это не компилируется... говорит о том, что access_process_vm неопределнный символ

anonymous
()
Ответ на: комментарий от anonymous

anonymous:

>access_process_vm() не экспортируется???

Ну тогда можно сделать cut&paste. Или же при компиляции указать -Wl,--defsym access_process_vm=..., адрес можно взять из System.map от вашего ядра.

Murr ★★
()
Ответ на: комментарий от anonymous

>правильная конструкция для получения значения адреса возврата по адресу [esp+2] ??

(unsigned long *)esp+2 - это по-моему [esp+8].
А нужно либо [esp] - (unsigned long *)esp или [esp+4] - (unsigned long *)esp + 1.

Murr ★★
()
Ответ на: комментарий от anonymous

mmput

а гдебы мне взять mmput ??? код... я прогрепил все дерево сорсов, но его кода чего-то не нашел... его имплементация находится в linux/sched.h но подключив этот хедер ничего не происходит - по-прежнему сакс (неопределнный символ)

anonymous
()
Ответ на: mmput от anonymous

mmput - это kernel/fork.c

можешь сделать emacs tags для ядра, чтобы было проще искать:
make TAGS

похоже, этот mmput много за собой тянет...
если из него еще что-то не экспортируется, то
можно попробовать просто заменить его на
atomic_dec(&mm->mm_users); в предположении,
что кто-то еще держит mm целевого процесса
(вполне разумное предположение).

Murr ★★
()
Ответ на: комментарий от anonymous

Угу.

Проверка нужна только если отпускается последняя ссылка на mm процесса, т.е. у mm больше нет пользователей. По сути твоей задачи можно предположить, что в процессе выполнения access_process_vm ты не останешься последним пользователем mm, поэтому можно считать, что ты не попадешь в внутрь блока mmput.

Murr ★★
()
Ответ на: комментарий от Murr

Кстати, чего я тебе голову морочу. Если нужно именно для текущего процесса, то можно просто copy_from_user сделать.

access_process_vm нужен только, если хочешь ковырять другой процесс.

Murr ★★
()
Ответ на: комментарий от anonymous

void mmput(struct mm_struct *mm) { /*if (atomic_dec_and_lock(&mm->mm_users, &mmlist_lock)) { list_del(&mm->mmlist); mmlist_nr--; spin_unlock(&mmlist_lock); exit_aio(mm); exit_mmap(mm); mmdrop(mm); } */ atomic_dec(mm->mm_users); }

можно ли заменить просто для моего примера тело функции на вышеизложенное?

anonymous
()
Ответ на: комментарий от anonymous

>void mmput(struct mm_struct *mm) { atomic_dec(&mm->mm_users); }

Да, в своем коде можно использовать такой mmput для access_process_vm.

Murr ★★
()
Ответ на: комментарий от Murr

Я пробывал работая с отладчиком отыскать "правильный" eip для своей программы, не получилось... хотя я даже писал copy_from_user(&eip, esp+0xC, 4).

Может есть возможность отыскать eip процесса иначе?

anonymous
()
Ответ на: комментарий от anonymous

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <asm/ptrace.h>
#include <asm/uaccess.h>
#include <asm/processor.h>

static int init_ttt(void) {
    struct pt_regs *r = (current->thread.esp0 - sizeof(struct pt_regs));
    unsigned long esp = r->esp;
    unsigned long eip1, eip = r->eip;

    copy_from_user(&eip1, ((char*)esp), 4);

    printk("esp = %lx, eip = %lx, eip1 = [esp] = %lx\n", esp, eip, eip1);

    return -EBUSY;
}

static void cleanup_ttt(void) {
}

module_init(init_ttt);
module_exit(cleanup_ttt);
MODULE_LICENSE("GPL");

Murr ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.