GPF on entering usermode

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
mohammedisam
Member
Member
Posts: 32
Joined: Tue Jan 06, 2015 5:15 pm

GPF on entering usermode

Post by mohammedisam »

Hi all
I have a problem when switching to usermode. I install the TSS as:

Code: Select all

void tss_install(uint16_t kernel_ss, uint16_t kernel_esp)
{
  memset(&tss_entry, 0, sizeof(tss_entry));
  tss_entry.ss0  = kernel_ss;
  tss_entry.esp0 = kernel_esp;
  tss_entry.cs = 0x0b;
  tss_entry.ss = 0x13;
  tss_entry.es = 0x13;
  tss_entry.ds = 0x13;
  tss_entry.fs = 0x13;
  tss_entry.gs = 0x13;
  printf("Flushing the TSS..\n");
  tss_flush();
}
Which I call from the kernel_early_entry() function as:

Code: Select all

  tss_install(0x10, 0);
this happens after I install the GDT. I then create a user address space, map the kernel space into user space (based on code from the BrokenThorn tutorials), and try to execute a test syscall (the syscall is number 0, which calls a twrite() function to write one letter to the screen, taking two parameters: pointer to char string, and it's length):

Code: Select all

.global task_test

task_test:
     mov $0x23, %ax	#user mode data selector is 0x20 + RPL 3
     mov %ax, %ds
     mov %ax, %es
     mov %ax, %fs
     mov %ax, %gs
     #create stack frame
     push $0x23		#SS
     push %ebx
     push %esp
     pushf
     push $0x1B		#CS user mode code selector is 0x18 + RPL 3
     lea (a), %eax
     push %eax
     iret
     a:
     mov $0, %eax
     mov $72, %ebx
     mov $1, %ecx
     int $0x80
     mov $0, %eax
     mov $69, %ebx
     mov $1, %ecx
     int $0x80
But it fails miserably with a GPF

Code: Select all

eip=008048090 ebp=0x0804A058 esp=0x0804A058
General Protection Fault Exception
At address 0x0010F556:0x00010012 EFLAGS [0x00010023] Error [0x00000008]
I know that I am missing something, but what is it?
cmdrcoriander
Member
Member
Posts: 29
Joined: Tue Jan 20, 2015 8:33 pm

Re: GPF on entering usermode

Post by cmdrcoriander »

mohammedisam wrote:Hi all

Code: Select all

void tss_install(uint16_t kernel_ss, uint16_t kernel_esp)
{
  /* snip */
  tss_entry.esp0 = kernel_esp;
  tss_entry.cs = 0x0b;
  tss_entry.ss = 0x13;
  tss_entry.es = 0x13;
  tss_entry.ds = 0x13;
  tss_entry.fs = 0x13;
  tss_entry.gs = 0x13;
  printf("Flushing the TSS..\n");
  tss_flush();
}
Why are you setting the TSS segment RPLs to usermode? The processor *loads* the new SS and ESP from the TSS on task switch, which means that the RPL has to be kernel mode.

Code: Select all

tss_entry.esp0 = kernel_esp;
tss_entry.ss = 0x10;
mohammedisam wrote:

Code: Select all

  tss_install(0x10, 0);
Why are you setting up the kernel stack at address 0?...
mohammedisam wrote:

Code: Select all

.global task_test

task_test:
     mov $0x23, %ax	#user mode data selector is 0x20 + RPL 3
     mov %ax, %ds
     mov %ax, %es
     mov %ax, %fs
     mov %ax, %gs
     #create stack frame
     push $0x23		#SS
     push %ebx
     push %esp
     pushf
     push $0x1B		#CS user mode code selector is 0x18 + RPL 3
     lea (a), %eax
     push %eax
     iret
     a:
     mov $0, %eax
     mov $72, %ebx
     mov $1, %ecx
     int $0x80
     mov $0, %eax
     mov $69, %ebx
     mov $1, %ecx
     int $0x80
The stack frame during an IRET is supposed to look like:

Code: Select all

SS
ESP
EFLAGS
CS
EIP
Where does that ebx you push come from?
mohammedisam wrote: But it fails miserably with a GPF

Code: Select all

eip=008048090 ebp=0x0804A058 esp=0x0804A058
General Protection Fault Exception
At address 0x0010F556:0x00010012 EFLAGS [0x00010023] Error [0x00000008]
I know that I am missing something, but what is it?
A copy of the x86 manual? ;)
mohammedisam
Member
Member
Posts: 32
Joined: Tue Jan 06, 2015 5:15 pm

Re: GPF on entering usermode

Post by mohammedisam »

cmdrcoriander wrote: Why are you setting the TSS segment RPLs to usermode? The processor *loads* the new SS and ESP from the TSS on task switch, which means that the RPL has to be kernel mode.
Hmm. I was trying code from BrokenThorn (the code in "Getting to Ring 3" tutorial didn't specify values for these registers :shock: ). To be honest, I didn't really understand why he put 0x13 into these registers.
cmdrcoriander wrote: Why are you setting up the kernel stack at address 0?...
It sounds stupid, yes, but I didn't know where to get (or how am I supposed to set) the kernel stack.
cmdrcoriander wrote: The stack frame during an IRET is supposed to look like:

Code: Select all

SS
ESP
EFLAGS
CS
EIP
Where does that ebx you push come from?
Yeah, that was wrong.
cmdrcoriander wrote: A copy of the x86 manual? ;)
You are probably right!! :D Still I culdn't get it to work, but I will certainly read the manual and see what can I improve.
cmdrcoriander
Member
Member
Posts: 29
Joined: Tue Jan 20, 2015 8:33 pm

Re: GPF on entering usermode

Post by cmdrcoriander »

mohammedisam wrote:
cmdrcoriander wrote: Why are you setting the TSS segment RPLs to usermode? The processor *loads* the new SS and ESP from the TSS on task switch, which means that the RPL has to be kernel mode.
Hmm. I was trying code from BrokenThorn (the code in "Getting to Ring 3" tutorial didn't specify values for these registers :shock: ). To be honest, I didn't really understand why he put 0x13 into these registers.
Obligatory 'you shouldn't use code if you don't know what it does' here... but the basic idea is that when an interrupt occurs from a less privileged level than the handler (ie. user-mode code jumps into the kernel for an interrupt - ring 3 to ring 0), the processor loads the *new* SS and ESP from the TSS's SS0 and ESP0 fields. The other segments aren't used at all unless you're using hardware task switching (someone correct me if I'm wrong about this - but I'm pretty sure).
mohammedisam wrote:
cmdrcoriander wrote: Why are you setting up the kernel stack at address 0?...
It sounds stupid, yes, but I didn't know where to get (or how am I supposed to set) the kernel stack.
Well, based on what I just told you about the TSS, you need to choose somewhere to put it, then set the TSS's ESP0 to wherever you chose.
mohammedisam wrote: You are probably right!! :D Still I culdn't get it to work, but I will certainly read the manual and see what can I improve.
Good luck! :)
Post Reply