Всем снова сдрасте. У меня новая проблема :) Мне нужно модифицировать (клонировать) обработчик 80 прерывания, она же функция system_call. Но он везде где я находил описан очень и очень хренова. Обычно все описание заключается в том что сказано: в eax передается номер вызываемой функции, он проверяется, далее запускается, если чтото не так то производются сложные действия для коректного возврата. Без каких либо подробностей. Мне нужно сделать практически аналогичный обработчик за некими маленькими отклонениями. А чтобы понять где эти маленькие поправления должны быть нужно понять как там все это работает, до последнего винтика. Прошу вашей помощи в разборе. Начнем по порядку.
Во первых сделаем для простоты такое упущение: ничего лишнего кроме как посмотреть номер вызываемой функции, вызвать ее и вернуть результат, ни надо, пока нужен самый минимум чтобы работал в идеальных условиях. И второе: нужно четко осознать те моменты где прямым образом фигурируют какие либо опоминания об пользовательском пространстве (дескрипторы GDT, DPL = 3, процесс вызвавший прерывание).
.pushsection .kprobes.text, "ax" # это относиться к обработчику или нет ?
# system call handler stub
ENTRY(system_call)
RING0_INT_FRAME # подготавливается стек ядра? Но как оно работает
pushl %eax # save orig_eax
CFI_ADJUST_CFA_OFFSET 4 # не понял что это ?
SAVE_ALL # сохраняем в стек все необходимые регистры
GET_THREAD_INFO(%ebp) # получаем инфу о треде вызвавшем прерывание ? Но кукую и для чего она ?
# system call tracing in operation / emulation
testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp) # проверка чего ?) Того что из данного треда можно делать системные вызовы ?
jnz syscall_trace_entry # сюда попадем если проверка не прошла, но в этой метке все равно может произойти вызов (см. ниже)
cmpl $(nr_syscalls), %eax
jae syscall_badsys # сюда прыгаем если номер системного переданный в eax неправильны, и далее возвращается ENOSYS
syscall_call:
call *sys_call_table(,%eax,4) # самое суть
movl %eax,PT_EAX(%esp) # кладем результат работы обратно в eax
syscall_exit:
LOCKDEP_SYS_EXIT # нах это ?
DISABLE_INTERRUPTS(CLBR_ANY) # make sure we don't miss an interrupt
# setting need_resched or sigpending
# between sampling and the iret
# На сколько я понял это некий аналог "For DISABLE_INTERRUPTS/ENABLE_INTERRUPTS (aka "cli"/"sti")"
TRACE_IRQS_OFF # не понял что это
movl TI_flags(%ebp), %ecx # кладем в ecx то чем можно идентифицировать тред который запустил прерывания, или его отдельное значение
testl $_TIF_ALLWORK_MASK, %ecx # current->work
# смотрим работаетли еще тред вызвавший прерывание ?
jne syscall_exit_work # сюда пошли если процесс уже не работает ?
restore_all: # а сюда для выхода в прерывания при работающем процессе ?
TRACE_IRQS_IRET # посмотрели что прерывание уже неработает ? Оо
restore_all_notrace: # подготовка в козврату в юзерспейс
movl PT_EFLAGS(%esp), %eax # mix EFLAGS, SS and CS
# Warning: PT_OLDSS(%esp) contains the wrong/random values if we
# are returning to the kernel.
# See comments in process.c:copy_thread() for details.
movb PT_OLDSS(%esp), %ah
movb PT_CS(%esp), %al
andl $(X86_EFLAGS_VM | (SEGMENT_TI_MASK << 8) | SEGMENT_RPL_MASK), %eax # макросы однозначно образую число 20403h, оно кладеться в eax
cmpl $((SEGMENT_LDT << 8) | USER_RPL), %eax # тут макросы образую также однозначно число 403h и эта проверка пройдет всегда, зачем она тогда О_о
CFI_REMEMBER_STATE # ???
je ldt_ss # returning to user-space with LDT SS
# какая то махинация со стеком
restore_nocheck:
RESTORE_REGS 4 # skip orig_eax/error_code
# восстанавливаем значения регистров (см. ниже)
CFI_ADJUST_CFA_OFFSET -4 # этот макрос на сколько я понял что то вроде метки на стеке откудова брать куда класть значения регистров
irq_return:
INTERRUPT_RETURN # вот тут то мы вызовем заветную инструкцию iret с помощью которой перейдем в usep space и произведем понижение привелегий (вот только я незаметил момента когда мы клали в стек необходимые ей параметры ?)
/* а все что дальше идет зачем ? */
syscall_trace_entry: # проверка не прошла прыгнули сюда и тут еще один шанс
movl $-ENOSYS,PT_EAX(%esp)
movl %esp, %eax
call syscall_trace_enter # что делает функция ?
/* What it returned is what we'll actually use. */
cmpl $(nr_syscalls), %eax
jnae syscall_call # и бац все равно можем сделать то что хотели, проделав какуюто преобработку, какую ?
jmp syscall_exit
END(syscall_trace_entry)
При таком вызове макроса
restore_nocheck:
RESTORE_REGS 4
.macro RESTORE_REGS pop=0
RESTORE_INT_REGS
1: popl %ds
CFI_ADJUST_CFA_OFFSET -4
/*CFI_RESTORE ds;*/
2: popl %es
CFI_ADJUST_CFA_OFFSET -4
/*CFI_RESTORE es;*/
3: popl %fs
CFI_ADJUST_CFA_OFFSET -4
/*CFI_RESTORE fs;*/
POP_GS \pop
.pushsection .fixup, "ax"
4: movl $0, (%esp)
jmp 1b
5: movl $0, (%esp)
jmp 2b
6: movl $0, (%esp)
jmp 3b
.section __ex_table, "a"
.align 4
.long 1b, 4b
.long 2b, 5b
.long 3b, 6b
.popsection
POP_GS_EX
.endm
.macro POP_GS pop=0 # что оно делает ?)
addl $(4 + \pop), %esp
CFI_ADJUST_CFA_OFFSET -(4 + \pop)
.endm
фух, несколько часов пост делал. Простите за мноо букф и еще больше вопросов, просто нужно все это понять %) Отвечайте по возможности лучше кусочками, так проще мазайку будет сложить.
PS. И кстати если получится сложить все это в единую картину с хорошим описание то это будет очень хороший мануал, коих нету на белом свете.