Date: Sun, 19 Jul 1998 20:18:57 -0400 From: "Allen Smith" <easmith@beatrice.rutgers.edu> To: Ollivier Robert <roberto@keltia.freenix.fr> Cc: security@FreeBSD.ORG Subject: Re: The 99,999-bug question: Why can you execute from the stack? Message-ID: <9807192018.ZM18945@beatrice.rutgers.edu> In-Reply-To: Ollivier Robert <roberto@keltia.freenix.fr> "Re: The 99,999-bug question: Why can you execute from the stack?" (Jul 19, 11:55pm) References: <199807192047.OAA02264@lariat.lariat.org> <19980719235532.A8630@keltia.freenix.fr>
next in thread | previous in thread | raw e-mail | index | archive | help
On Jul 19, 11:55pm, Ollivier Robert (possibly) wrote: > According to Brett Glass: > > segmentation model normally prevents this, and there's additional hardware > > in the MMU that's supposed to be able to preclude it. Why does the OS leave > > this gigantic hole open? Why not just close it? > > As it has been said several times already, gcc itself make code on the > stack a bit difficult to forbid. It generates code on the stack for > "trampolines". According to the ?guy?, Solar Developer, who wrote the linux patch, in 199704131906.QAA06271@sun1.ideal.ru: ____ About GCC trampolines -- yes, there is a problem, but in reality it turns out to be quite easy to solve; also, nested functions, and especially those which address gets passed somewhere else, are not common in real world applications -- one of the reasons is that it's a GNU C extension. Since most programs will never use the trampolines, it makes sense to run them with non-executable stack, and enable stack execution permission for those that really need it. This can be done automatically, by modifying the GPF handler to switch back to the huge code segment (which covers the stack) and re-executing the instruction, unless it was a RET. Since most buffer overflows can only be exploited by overwriting the return address, this will still make them unexploitable (RET has to be the instruction to pass the control onto the stack), while C programs will normally only use CALL, and it is extremely unlikely that some code will use RET for that purpose (this can never happen for pure C programs compiled with GCC). Note that such emulation won't make the things run any slower since only one GPF per entire process life may get generated (after that the stack remains executable for this entire process). About me breaking the entire signal handling -- wrong, I handle this case specially from the very beginning, by temporary switching to the huge code segment for the time of signal handler execution. This leaves potential buffer overflows in signal handlers exploitable, but there seems to be no other simple way for the kernel to put the necessary return code in user program's address space (remember, signal handlers have to return with a plain RET, but they need to return to the kernel, so some extra code in the user space is required, which would get jumped to by the RET, and jump into the kernel). ____ Admittedly, I don't know enough on x86 programming to know whether or not this will work on FreeBSD; it appears to on Linux. -Allen -- Allen Smith easmith@beatrice.rutgers.edu To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe security" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?9807192018.ZM18945>