Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 205 Vote(s) - 3.76 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Why does iret from a page fault handler generate interrupt 13 (general protection fault) and error code 0x18?

#1
I am writing a kernel by myself, and after the first page error interrupt handler, when IRET is executed, it causes an interrupt 13(general protection), and error code is 0x18. I don't know what is wrong, the content pushed on the stack comes from the cpu.

Here is the register state when interrupt occurs, and memory where the registers were stored.**In addition, IRET is returned from a page error interrupt handler.**

It is sure that %ESP is the same before IRET executing and interrupt occurring.

![enter image description here][1]


![enter image description here][2]


[1]:

[2]:
Reply

#2
If the exception is from `IRET` itself, then most likely `IRET` is failing to restore one of the saved segment registers, but the value (8 or 0x18, btw?) is somehow wrong. It can be wrong because you never (re)initialized the register in protected mode or your handler set it to a bad value before doing `IRET` or something happened to the GDT...

**EDIT**: From the picture it's apparent that the page fault handler didn't remove the exception code (value of 4 at address in `ESP`) before executing `IRET`. And so `IRET` interpreted 4 as the new value for `EIP`, 0x1000018 as the new value for `CS` and 0x23 as the new value for `EFLAGS`, whereas it should be using 0x1000018, 0x23 and 0x3206 for those three registers. Obviously, a data segment selector (which 0x1000018 is interpreted as after truncation to 0x0018) cannot be loaded into `CS` and this causes #GP(0x18).
Reply

#3
Expanding on Alexey:

When some interrupts happen (but not others), they automatically push a 4 byte error code to the stack. Page fault is one of them.

This error code contains extra information about the interrupt.

[Intel Manual Volume 3 System Programming Guide - 325384-056US September 2015]( ) Table 6-1. "Protected-Mode Exceptions and Interrupts" column "Error Code" tells us exactly which interrupts push the error code, and which do not.

38.9.2.2 "Page Fault Error Codes" explains what the error means.

So you will need either:

pop %eax
/* Do something with %eax */
iret

Or if you want to ignore the error code:

add $4, %esp
iret

For a minimal example, see [this page handler](

[To see links please register here]

) and try commenting out the `pop`.

Compare the above with a [Division error exception](

[To see links please register here]

) which does not need to pop the stack.

Note that if you do simply `int $14`, no extra byte gets pushed: this only happens on the actual exception.

A neat way to deal with this is to push a dummy error code `0` on the stack for the interrupts that don't do this to make things uniform. James Molloy's tutorial [does exactly that](

[To see links please register here]

).

The Linux kernel 4.2 seems to do something similar. Under [arch/x86/entry/entry64.S](

[To see links please register here]

) it models interrupts with `has_error_code`:

trace_idtentry page_fault do_page_fault has_error_code=1

and then uses it on the same file as:

.ifeq \has_error_code
pushq $-1 /* ORIG_RAX: no syscall to restart */
.endif

which does the push when `has_error_code=0`.

Related question:

[To see links please register here]

Reply

#4
I know this is a very old question, but adding my answer here for the sake of completeness.

Depending on your assembler, you may need to explicitly use `iretd` (the 32-bit variant) instead of `iret` (16-bits). The CPU will raise a GP if you try to use the 16-bit variant to return to a 32-bit segment.
Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through