Comment by zaarn
8 years ago
> (except - I think interrupts use the kernel stack? Otherwise triggering an interrupt would clobber the red zone, which should be preserved, since it pushes the return address and flags IIRC? So interrupts don't "use" the red zone)
Interrupts may use the kernelstack, you can use the userstack but this is trouble if they don't uphold the redzone, which they may not.
The redzone is a mere suggestion the compiler may apply when it exposes functions elsewhere. The stack is mostly free game.
When you are writing a kernel, the red zone is off, I may have worded this wrong previously. The userspace should use the redzone, the kernel can't, interrupts must not assume a redzone since they don't have the time to add or sub from the RSP.
>wouldn't that also mean any function can assume the 128 bytes below RSP are actually mapped?
The stack is always sort of mapped and not at all. Normally the stack region is unmapped in the page table. Should a process run the stack into an unmapped region, the OS will generally map this region if memory is available. And because programmers are silly, the OS will also happily map memory way above the last mapped page if accessed.
Go setting up a 104 byte stack only means that the runtime assumes the vDSO will not use more than 104 bytes of stack and another go routine may be allocated just after those 104 bytes. So if the vDSO does it's stack probe 4k into foreign stack just under the current thread stack, it will cause a race condition on the memory write.
The stack probe is there to prevent overflowing the stack into the heap, there is always a guard page between user memory and user stack which will kill the task if it is accessed. So the probe will jump into this guard page and kill the program if any funny business is going on.
But shouldn't Go really assume that the vDSO (or any other external function) will use at least 128 bytes of stack then? If go only reserves 104 bytes, then even without all this 4k probe business, there would be a risk that the vDSO could overwrite up to 128 bytes (which could be another go-routine's stack, or an unmapped page (which would probably cause a segfault if Go's trap handler for segfaults doesn't expect an access there, instead of the OS or the trap handler silently mapping more memory))? I mean, isn't the assumption flawed from the beginning by reserving less than 128 bytes?
Also, regarding:
> Interrupts may use the kernelstack, you can use the userstack but this is trouble if they don't uphold the redzone, which they may not.
I don't see how this is possible without corrupting the redzone. The CPU pushes the return RIP and the flags onto RSP when an interrupt occurs, which would overwrite parts of the redzone, so the damage would be done on the userspace stack even before the first instruction of the interrupt handler is executed)
> I mean, isn't the assumption flawed from the beginning by reserving less than 128 bytes?
Not technically since the vDSO does not use more than 104 bytes of stack. The problem was the compiler assuming wrongly there might be more to have and writing data above this limit.
The actual stack usage of a vDSO is not documented afaik.