GPF on jum to less privalged code

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.
ed_tait

GPF on jum to less privalged code

Post by ed_tait »

hello,

i'm new to kernel development and have sucessfully switched to pmode and implemented an idt and have turned on paging.

when i try to jump to code at dpl 3 i get a general protection fault.

my gdt looks like this

Code: Select all

gdt:                    ; Address for the GDT

gdt_null:               ; Null Segment
        dd 0
        dd 0

gdt_code:               ; Code segment, read/execute, nonconforming
        dw 0FFFFh
        dw 0
        db 0
        db 10011010b
        db 11001111b
        db 0

gdt_data:               ; Data segment, read/write, expand down
        dw 0FFFFh
        dw 0
        db 0
        db 10010010b
        db 11001111b
        db 0
        
gdt_interrupts:         ; Interrupt segment, read/execute, nonconforming
        dw 0FFFFh
        dw 01000h       ; Start at address 01000h
        db 0
        db 10011010b
        db 11001111b
        db 0
gdt_apps:         ; Interrupt segment, read/execute, nonconforming            
        dw 0FFFFh
        dw 0
        db 0
        db 10111011b
        db 11001111b
        db 0      

gdt_end:                ; Used to calculate the size of the GDT


gdt_desc:                       ; The GDT descriptor
        dw gdt_end - gdt - 1    ; Limit (size)
        dd gdt                  ; Address of the GDT
when i perform a jump to some test code the GPf fires:

Code: Select all

mov ax, 0febch ; for debuging 

jmp 18h:test_user

; we never get here there is a General protection fault
test_user
mov ax, 1234h ; for debuging
int 3 ;break point
The hex dump indicates that the problem is with the jmp instruction scince the value of ax is still 0febch.

bochs prints the message:
check_cs: non-conforming code seg descriptor dpl != cpl

but my kerel runs at ring 0 !?

does anyone know why i cant jum to this code?

Thank you.
bluecode

Re:GPF on jum to less privalged code

Post by bluecode »

hi,

I don't think it is possible to just jump to a less priviledged code!
You have to at least add a TSS and do software or hardware based task switching to execute some cpl3 code.
Ryu

Re:GPF on jum to less privalged code

Post by Ryu »

The GDT had conforming bit off, what was in the Intel manual:
Nonconforming code segment (without using a call gate): The DPL Indicates the privilege level that a program or task must be at to access the segment. For an example if the DPL of a nonconforming code segment is 0, only programs running at CPL of 0 can access the segment.

Try setting all GDTs to conforming and create a callgate descriptor for the destination DPL 3 descriptor.

edit: Just to add to this, you can use a nonconforming segment to access a conforming segment if you have a call gate style, so basically the call gate descripter should be the same DPL as the nonconforming CPL and must be nonconforming. But this wouldn't make sense to me, as you are in CPL 0 segment trying to get into a DPL 3, you should be using a conforming descriptor, and DPL 3 descriptor should also be conforming. If your in a nonconforming segment your stuck in the same CPL and cannot enter conforming segments even at the same privilege level, otherwise GPF will get you.

edit: Okay, after reading it throughly, I was mixed up with CPL 0 and lowest privilege ???.
ed_tait

Re:GPF on jum to less privalged code

Post by ed_tait »

hello again,

i've looked into task switching and have sucessfully immplemnted task switching between kernel threads

how ever, i still cant switch from the kernel to a user therte useing the change stack -> iret system, bochs produces the same error:

check_cs: non-conforming code seg descriptor dpl != cpl

the following things are on the stack before the iret:

Code: Select all

ss ; 28h
esp ;100000h
eflags  ; 0
cs ; 20h
eip ; task
has any one got any ideas what i'm doing wrong?

thank you.
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re:GPF on jum to less privalged code

Post by Brendan »

Hi,
ed_tait wrote:how ever, i still cant switch from the kernel to a user therte useing the change stack -> iret system, bochs produces the same error:

check_cs: non-conforming code seg descriptor dpl != cpl

the following things are on the stack before the iret:

Code: Select all

ss ; 28h
esp ;100000h
eflags  ; 0
cs ; 20h
eip ; task
The CPU's CPL is stored in the lowest 2 bits of the CS register and the lowest 2 bits of the SS register. The DPL comes from the descriptor in the GDT. If the DPL in the descriptor is set to 3, then you'd need to set CPL to 3 in CS and SS.

Bascially, CS on the stack should be 0x23 and SS on the stack should be 0x2B (and they must both point to segment descriptors that have DPL=3).


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
mystran

Re:GPF on jum to less privalged code

Post by mystran »

Also, I'm not quite sure you should use EFLAGS=0 while it's unlike to have anything much having to do with this.

Basicly, bit 1 (counting from 0) should always be set to 1. IIRC it's hardwired anyway, but it's good idea to set it in any case, if for nothing else, then future compability. You can't know what it's going to mean tomorrow.

I'd also set IF and AC, but that naturally depends.

Anyway, if you want clear set of flags, then use EFLAGS=2, so it conforms with what the holy manuals rule.
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:GPF on jum to less privalged code

Post by Pype.Clicker »

The whole processor is organized so that you only jump to higher privilege levels. Task switch may of course bypass this, but not "non-conforming code segments". The purpose of non-conforming segments is to be able to have a part of code (presumably a library) that can be invoked from any CPL with a single segment. E.g. if you're at DPL2, the new segment will run with privilege level 2 ... if you're at CPL1, it will run with privilege 1, etc.
This has virtually no use nowadays and i wonder whether it has ever been used ...

maybe prior the addition of paging ...

What people usually do when they want their kernel to start user-level code is to push a "return state" on the kernel stack and then do an IRET, so that the CPU believes you're returning to user code that previously called your kernel. That does work.
Ryu

Re:GPF on jum to less privalged code

Post by Ryu »

When I looked at the little doodles in the Intel manuals, I was wondering where they ever apply a non-conforming segment to the real world. I'm actually curious to know if anyone made use of it.
paulbarker

Re:GPF on jum to less privalged code

Post by paulbarker »

The only place I could see a use for this is a core library which contains functions like abs(), etc. which can run unchanged in user mode or kernel mode. I might make use of this in my OS, I might not... I'll cross that bridge when I get to it.
ed_tait

Re:GPF on jum to less privalged code

Post by ed_tait »

hello again.

i think i've made progress, i've added a tss for switches to ring 3.

am i supposed to execute the ltr instruction just before the switch or in the initiation phase?

should i use the sellector for the tss in the gdt like so:

Code: Select all

ltr [30h] ; tss selector
if so i get a gpf:

fetch_raw_descriptor: GDT: index (ff57)1fea > limit (37)

my gdt entry for the tss looks like so:

Code: Select all

 gdt_tss:                     
        dw 104 ; 104 bytes
        dw 0
        db 10000b
        db 01011001b
        db 00001001b
        db 0b
;
; the tss itself looks like this:
;

       backlink  dw 0
        __blh dw 0
       
       esp0 dd   0
       ss0 dw   0
       __ss0h dw 0
       
       esp1 dd 0   
       ss1   dw 0   
       __ss1h dw 0
       
       esp2 dd   0 
       ss2 dw   0
       __ss2h dw 0 
      
      _cr3  dd 0   
      eip dd  0   
      eflags dd 0   
      _eax dd    0
      _ecx dd    0
      _edx dd    0
      _ebx dd    0
      _esp dd    0 
      _ebp dd    0
      _esi dd    0
      _edi dd    0
      _es dw    0
      __esh dw  0
      _cs dw     0
       __csh dw 0
      _ss dw     0
       __ssh dw 0
      _ds dw     0
      __dsh dw  0
      _fs dw     0
       __fsh dw 0
      _gs dw     0
      __gsh dw  0
      ldt dw      0
       __ldth dw 0
      trace dw   0
       bitmap dw 0
thank you.
Ryu

Re:GPF on jum to less privalged code

Post by Ryu »

paulbarker wrote: The only place I could see a use for this is a core library which contains functions like abs(), etc. which can run unchanged in user mode or kernel mode. I might make use of this in my OS, I might not... I'll cross that bridge when I get to it.
My growing standard C runtime library (about 16 routines so far) all follow DS=ES,SS,CS = nominal base rule, this allows me to use the library in windows developement too. :)

I think I have uses for non-conforming segments because I have high hopes for my kernel to run non-paging privilege level 0 programs and keeping it stable.
mystran

Re:GPF on jum to less privalged code

Post by mystran »

Where you load your TR depends on how you do thread swithing. If you do it in software, you can load it once when you init TSS (I do it like that) and then just change the esp0 in it, since that's pretty much all you ever need, although ss0 needs a sane (constant) value too.

As for hardware switching, somebody that uses it can tell, I've forgot all about it (on purpose, really).
ed_tait

Re:GPF on jum to less privalged code

Post by ed_tait »

if you use sack based task switching do you need a tss or can you store esp0 in another way?
mystran

Re:GPF on jum to less privalged code

Post by mystran »

You need one TSS per processor to hold whatever is the current esp0. For system calls there's another way with sufficiently new processors, but you still need to handle interrupts and exceptions, so you still need TSS anyway.
paulbarker

Re:GPF on jum to less privalged code

Post by paulbarker »

The correct places to use TSS's in stack based switching are 1 per processor holding esp0/ss0, one for a double fault handler and one for an NMI handler.

I know this is going off topic but if I have 1 double fault handler for the entire system, what would happen if a processor tried to doube fault at the same time as another (so the busy flag for the TSS is set)? Would this cause a triple fault (reset) or would the 2nd processor wait for the first to finish?
Post Reply