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)
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.
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.
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.
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.
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).
Why are 8 bytes reserved at the "bottom" of kernel stack when it is created?
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With