One aspect of x86-64 I've been quite curious about is the addition of page permissions (which can be used to implement a non-executable user stack), and although not very technical, this New Scientist article appears to confirm their existance.
For those of you who don't know about them, page permissions, which have existed on most RISC architectures for years, allow code executing in kernel context to control what operations may be performed on a specific page in process context. Load operations may only be performed on pages marked readable, store operations may only be performed on pages marked writable, and the instruction pointer may only point at addresses inside of a page marked executable. If the permissions are violated while in process context, a trap (or "exception"/CPU generated interrupt in x86 semantics) is raised. This can be helpful in preventing exploitation of buffer overflows (at least for code running in process context), as it eliminates the possibility of filling a stack buffer with instructions and overwriting the return pointer of the current stack frame with the buffer's address. When the processor attempts to jump to the address of a buffer in a non-executable page (all pages used by the stack should be marked non-executable), a trap is raised and program execution will likely be terminated, depending on the behavior of the trap handler.
Unfortunately the full benefits of page protections are not currently being fully leveraged, as pages used for stack space are still marked writable (meaning any sort of store operation is allowed on those pages) because a process must be able to manipulate its own stack in current ABI designs, and of course store operations to stack variables will almost always be necessary.
The possibility of exploitation of buffer overflows could be completely eliminated using page permissions, but the implementation would be slow and far from pretty. The solution would be a stack managed completely in kernel context, with seperate pages for stack frames (accessable in kernel context only), stack data (r/w), machine instructions (x), and heap data (r/w). In such an implementation, a process would invoke a function by making a system call, which would handle construction/addition or removal of a stack frame, and would store stack variables in a separate page. This would require two context switches per function invocation, and is thus rather impractical, especially considering most threads implementations have threads store their stacks in the data heap, as the heap must be serializable but the stack is typically not. The kernel would need to maintain seperate stacks for each thread in order for this to function in a multithreaded environment.
For those of you who don't know about them, page permissions, which have existed on most RISC architectures for years, allow code executing in kernel context to control what operations may be performed on a specific page in process context. Load operations may only be performed on pages marked readable, store operations may only be performed on pages marked writable, and the instruction pointer may only point at addresses inside of a page marked executable. If the permissions are violated while in process context, a trap (or "exception"/CPU generated interrupt in x86 semantics) is raised. This can be helpful in preventing exploitation of buffer overflows (at least for code running in process context), as it eliminates the possibility of filling a stack buffer with instructions and overwriting the return pointer of the current stack frame with the buffer's address. When the processor attempts to jump to the address of a buffer in a non-executable page (all pages used by the stack should be marked non-executable), a trap is raised and program execution will likely be terminated, depending on the behavior of the trap handler.
Unfortunately the full benefits of page protections are not currently being fully leveraged, as pages used for stack space are still marked writable (meaning any sort of store operation is allowed on those pages) because a process must be able to manipulate its own stack in current ABI designs, and of course store operations to stack variables will almost always be necessary.
The possibility of exploitation of buffer overflows could be completely eliminated using page permissions, but the implementation would be slow and far from pretty. The solution would be a stack managed completely in kernel context, with seperate pages for stack frames (accessable in kernel context only), stack data (r/w), machine instructions (x), and heap data (r/w). In such an implementation, a process would invoke a function by making a system call, which would handle construction/addition or removal of a stack frame, and would store stack variables in a separate page. This would require two context switches per function invocation, and is thus rather impractical, especially considering most threads implementations have threads store their stacks in the data heap, as the heap must be serializable but the stack is typically not. The kernel would need to maintain seperate stacks for each thread in order for this to function in a multithreaded environment.
Comment