Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In ARM Linux, what is the purpose of the few bytes reserved at the "bottom" of kernel stack for each thread

Question:

Why are 8 bytes reserved at the "bottom" of kernel stack when it is created?

Background:

We know that struct pt_regs and thread_info share the same 2 consecutive pages(8192 bytes), with pt_reg located at the higher end and thread_info at the lower end. However, I noticed that 8 bytes are reserved at the highest address of these 2 pages:

in arch/arm/include/asm/threadinfo.h

#define THREAD_START_SP     (THREAD_SIZE - 8)
like image 964
CodingNow Avatar asked Aug 11 '14 07:08

CodingNow


People also ask

What is the kernel stack of a process used for?

The kernel stack is also used for interrupt handler execution, for the interrupts that occur while a particular thread is running. As we have talked about already, the interrupts are almost always doing something for another, blocked process/thread.

Why do threads have a kernel stack?

With separate user and kernel stacks for each process or thread, we have better isolation. Problems in the user stack can't cause a crash in the kernel. This isolation makes the kernel more secure because it only trusts the stack area that is under its control.

Why do we switch from the user's stack to a kernel stack when we enter the kernel?

One of the reasons for having a separate kernel stack is that the kernel needs a place to store information where user-mode code can't touch it. That prevents user-mode code running in a different thread/process from accidentally or maliciously affecting execution of the kernel.

What is kernel stack overflow?

Cause. This error occurs when your application code attempts to call a new method and it has already reached the maximum number of embedded method call levels (which is currently 256). One cause can be recursive method calls with no clear exit conditions.


2 Answers

This way you can access to thread_info structure just by reading stack pointer and masking out THREAD_SIZE bits (otherwise SP initially would be on the next THREAD_SIZE block).

static inline struct thread_info *current_thread_info(void)
{
        register unsigned long sp asm ("sp");
        return (struct thread_info *)(sp & ~(THREAD_SIZE - 1));
}

Eight bytes come from the ARM calling convention that SP needs to be 8-byte aligned.

Update: AAPCS 5.2.1.1 states:

A process may only access (for reading or writing) the closed interval of the entire stack delimited by [SP, stack-base – 1] (where SP is the value of register r13).

Since stack is full-descending

THREAD_START_SP (THREAD_SIZE - 8)

would enforce this requirement probably by illegal access to next page (segmentation fault).

like image 181
auselen Avatar answered Oct 10 '22 22:10

auselen


Why are 8 bytes reserved at the "bottom" of kernel stack when it is created?

  1. If we reserve anything on the stack, it must be a multiple of eight.
  2. If we peek above the stack, we like to make sure it is mapped.

Multiple of eight

The stack and user register needs to be aligned to 8 bytes. This just makes things more efficient as many ARMs have a 64bit bus and operations on the kernel stack (such as ldrd and strd) may have these requirements. You can see the protection in usr_entry macro. Specifically,

#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (S_FRAME_SIZE & 7)
#error "sizeof(struct pt_regs) must be a multiple of 8"
#endif

ARMv5 (architecture version 5) adds the ldrd and strd instructions. It is also a requirement of the EABI version of the kernel (versus OABI). So if we reserve anything on the stack, it must be a multiple of 8.

Peeking on stack

For the very top frame, we may want to take a peek at previous data. In order not to constantly check that the stack is in the 8K range an extra entry is reserved. Specifically, I think that signals need to peek at the stack.

like image 42
artless noise Avatar answered Oct 10 '22 23:10

artless noise