Page 1 of 1

Linux kernel GDT layout

Posted: Sat Jan 30, 2021 11:31 am
by growlnx
Hi all,

A way to "disable" segmentation is use on big segment (flat model), right?
Image from book "Understanding the LINUX KERNEL THIRD EDITION"
Image from book "Understanding the LINUX KERNEL THIRD EDITION"
Image from book "Understanding the LINUX KERNEL THIRD EDITION"
Image from book "Understanding the LINUX KERNEL THIRD EDITION"
Why dont' use only one segment?

Does the DPL will really make difference here?

Re: Linux kernel GDT layout

Posted: Sat Jan 30, 2021 11:38 am
by nexos
No matter what, you will always need 4 segments. Note that these segments are all flat. The reason why is because all instruction access implicitly use the CS register, all data access use the DS register, and all stack access use the SS register. DS and SS can share a segment, but CS requires its own format. This means that a ring 0 only OS will need two segments, kernel code and kernel data. User mode requires two segments as well, user code and user data. User code / data must have a different segment then kernel code / data, as otherwise, user code could trap into kernel mode with ease, hence destroying security. Also, every CPU requires its own descriptor for the TSS, which goes into the TR register. The TSS is needed for user mode to kernel mode transitions.

Re: Linux kernel GDT layout

Posted: Sat Jan 30, 2021 12:29 pm
by growlnx
nexos wrote:User code / data must have a different segment then kernel code / data, as otherwise, user code could trap into kernel mode with ease, hence destroying security. Also, every CPU requires its own descriptor for the TSS, which goes into the TR register. The TSS is needed for user mode to kernel mode transitions.
With this layout of GDT will the user be able to read kerneland instructions (ignoring the paging protections)?

The DPL flag will restrict the user to execute ring 0 instructions, but what about change?

Re: Linux kernel GDT layout

Posted: Sat Jan 30, 2021 1:32 pm
by nullplan
growlnx wrote:With this layout of GDT will the user be able to read kerneland instructions (ignoring the paging protections)?

The DPL flag will restrict the user to execute ring 0 instructions, but what about change?
Not entirely sure what you mean here but user code will run at CPL 3, and thus not qualify for supervisor pages, which is why access to kernel code and data will trap. User code can also not change the CPL without simultaneously changing rIP. And user code cannot even read supervisor pages, never mind changing them.

Re: Linux kernel GDT layout

Posted: Sun Jan 31, 2021 8:51 pm
by growlnx
nullplan wrote:
growlnx wrote:With this layout of GDT will the user be able to read kerneland instructions (ignoring the paging protections)?

The DPL flag will restrict the user to execute ring 0 instructions, but what about change?
Not entirely sure what you mean here but user code will run at CPL 3, and thus not qualify for supervisor pages, which is why access to kernel code and data will trap. User code can also not change the CPL without simultaneously changing rIP. And user code cannot even read supervisor pages, never mind changing them.
I'm imagining a fictional scenario where the kernel does not implement pagination/virtual memory, where it only has this GDT segmentation layout.

In this scenario, will the user be able to edit kerneland code/instructions?

Re: Linux kernel GDT layout

Posted: Sun Jan 31, 2021 10:08 pm
by nullplan
growlnx wrote:In this scenario, will the user be able to edit kerneland code/instructions?
Well, yes. If you throw away all paging protection yes, the user is able to write anywhere. That's rather like saying "if you remove the lock from my door, the door will be insecure", but there you go.

Re: Linux kernel GDT layout

Posted: Mon Feb 01, 2021 3:34 am
by bzt
growlnx wrote:I'm imagining a fictional scenario where the kernel does not implement pagination/virtual memory, where it only has this GDT segmentation layout.

In this scenario, will the user be able to edit kerneland code/instructions?
Your question is wrong. The privilege level is set up when the CS register is loaded. You simply cannot load CS with DPL 3 if it's pointing to a GDT entry with RPL 0, that would trigger a general protection fault. The reason for the two separated segment descriptors in GDT is because user code points to one, and kernel code to another, that's what actually creates the separation between user space space (ring 3) and kernel space (ring 0) with different CPLs. Add to that that there's a need for separated code and data segments, and you'll have 4 segments at minimum: user data, user code, kernel data, kernel code.

Cheers,
bzt

Re: Linux kernel GDT layout

Posted: Mon Feb 01, 2021 4:16 am
by rdos
nullplan wrote:
growlnx wrote:In this scenario, will the user be able to edit kerneland code/instructions?
Well, yes. If you throw away all paging protection yes, the user is able to write anywhere. That's rather like saying "if you remove the lock from my door, the door will be insecure", but there you go.
Yes, and so userland CS & DS should not map kernelland. If the kernel is loaded in upper memory, this is easily fixed by setting a lower limit for the userland flat selector.

Also, if pointers from userland use userland flat selectors that don't map kernelland this also means that pointers passed to kernel with syscalls cannot be used to sabotage kernel space data or code.

Re: Linux kernel GDT layout

Posted: Mon Feb 01, 2021 4:56 am
by bzt
I'm still not sure if we understand the question, it's wage. Segmentation and paging are two totally independent things, and the CPL is defined by the segment, so it works even without paging.

In protected mode, the segment descriptors also specify the base and the size of the segment. We are only talking about "flat model", when all the segments have base 0 and size -1.
In non-flat model, you can configure each segment to point to a different area in memory, so you can separate user space and kernel space without paging.

But, because you can use flat model and still want to separate user and kernel space, you can also enable paging, and force a more finely granulated, page-based security via the mapping.

That was all for protected mode. In long mode, segments are not used, so there's no point in "disabling" the segmentation in the first place. It is already disabled, and you can't enable it. Segment descriptors are merely loaded to set the CPL flag in CS, and it is totally irrelevant what the other bits are, what you set up in base and size, you'll always get the flat model. Also unlike in protected mode, paging must be enabled (so you can't disable it), therefore security via mapping is the one and only (and mandatory) way to separate which memory can be accessed from user land.

Does this makes sense to you?

Cheers,
bzt

Re: Linux kernel GDT layout

Posted: Mon Feb 08, 2021 4:56 pm
by growlnx
bzt wrote:
growlnx wrote:I'm imagining a fictional scenario where the kernel does not implement pagination/virtual memory, where it only has this GDT segmentation layout.

In this scenario, will the user be able to edit kerneland code/instructions?
Your question is wrong. The privilege level is set up when the CS register is loaded. You simply cannot load CS with DPL 3 if it's pointing to a GDT entry with RPL 0, that would trigger a general protection fault. The reason for the two separated segment descriptors in GDT is because user code points to one, and kernel code to another, that's what actually creates the separation between user space space (ring 3) and kernel space (ring 0) with different CPLs. Add to that that there's a need for separated code and data segments, and you'll have 4 segments at minimum: user data, user code, kernel data, kernel code.

Cheers,
bzt
Cool, now I understand the real reason for having a segment with the same mapping for ring 3. It is because of the general protection fault.