Greg, On 3 Oct 2012, at 12:00 AM, Greg Ungerer wrote:
For stack checking to be useful, I need two things: 1) it has to detect the (preferably impending) occurrence of a stack overflow, and 2) it has to give notice that it has occurred. For task 2), I'm trying to figure out how to enable the typical Linux behavior, such as a tty message "Illegal instruction (core dumped)", and/or register dumps on the tty or in /var/log/messages. >> I use trap #7 because the conditional trap instructions use trap vector #7. > > Issuing a trap #7 will just cause the kernel to send a SIGILL signal to the > process. If it is not caugth it will probably cause process termination. > (All software traps, except 0, do this on ColdFire). So far I found where the vectored interrupts are setup in arch/m68k/kernel/vectors.c. trap #7 (VEC_TRAP7, I assume) is routed to ENTRY(trap) in arch/m68k/kernel/entry_mm.S, which then calls trap_c() in arch/m68k/kernel/traps.c. traps_c decides to signal SIGILL(ILL_ILLTRAP) and calls force_sig_info() in kernel/signal.c. That's as far as I've gotten. I think maybe kernel/exec.c is where I should look next for what notification options there are. >> overflow: overflow: >> > move.l __stack_start@GOT(%a5),%a0 >> > lea (404,%a0),%a0 >> > cmp.l %sp,%a0 >> > bls.s .+4 >> > trap #7 > > It would be pretty easy to just add a whole bunch of debug trace in > the kernel when you get this - just for debugging purposes of course. > Probably makes no sense for a user space process to catch the SIGILL > in this case. You are out of stack and drastic action is needed. I'm still looking for the conditions it takes to have something like show_registers() in arch/m68k/kernel/traps.c called when the trap occurs. >>> Be mindful that on older ColdFire Cores, that only had a single A7, >>> then the CPU will be pushing the exception frame onto the user >>> space stack (so an extra 8 bytes). [snip] >> It only checks that 4 bytes are available. (To account for a frame pointer? >> That's my guess. I changed 4 to INCOMING_FRAME_SP_OFFSET in the stack >> checking code. There is not always a frame pointer, though, like in this >> case.) Maybe some minimum value would be a good idea, just to account for >> the single A7 you describe -- so some minimum trap or O/S call could be >> handled. It's easy enough to modify the stack checking code. Not sure, >> though, what flags tell the compiler there is only one A7. > > There is no need to tell the compiler, it doesn't really care. That is > only something that the Operating System cares about. User processes are > completely oblivious to the implementation of exception frames - and > that is what you want. Just to be completely safe (picky, I know). I guess gcc -mcpu could be used to figure out whether there is a separate interrupt stack. > On your example junk function above, if you are running that on a > ColdFire with a single A7 then when you hit "trap #7" the CPU will > push the 8 bytes of the exception frame onto the current user stack, > and then switch to supervisor mode (ie enter the kernel). On most > other CPU types, and ColdFires that have separate supervisor and user > A7 registers, the CPU will switch to supervisor mode, switch to using > the kernels A7 and then push the 8 bytes of exception frame. I assume the same is true for interrupts: the single A7 has to be able to at least hold the current PC and PSW. Another good reason to make sure the stack has at least 8 bytes. > You would have to be unlucky to be 8 bytes short, that is why I said > to just be mindfull of this happening. Agreed. As for task 1), I've been working my way through fs/binfmt_flat.c. I found load_flat_binary() handles the "main" executable; load_flat_shared_library() handles libraries. They both call load_flat_file() to do most of the work. From what I can tell so far, the initial memory layout of the "main" executable is: <--- memp + memp_size (physical memory address) unused (space for bss, stack, environment variables, command-line arguments) shared library table (allocated) relocation table (read from executable, released after relocations are done) data (read from executable) text (read from executable) <--- memp (physical memory address) After relocation (ready for execution), the memory layout is: <--- memp + memp_size (physical memory address) environment variables command-line arguments argv[] <--- initial sp stack <--- memp + memp_size - stack_len (physical memory address) brk <--- start_brk (physical memory address) <--- __STACK_START <--- datapos + data_len + bss_len (physical memory address) bss <--- datapos + data_len (physical memory address) data <--- datapos (physical memory address) text <--- memp/textpos (physical memory address) The crux of my problem seems to be that __STACK_START is not really the "top" of the stack. There is an area identified as BRK that can be overwritten before the stack check logic trips. I do not know what it is used for or what can happen if it gets clobbered. binfmt_flat.c honors a header flag, FLAT_FLAG_KTRACE, to print out the executable layout. I'll try to figure out how to enable that. > > Regards > Greg > > > -- > ------------------------------------------------------------------------ > Greg Ungerer -- Principal Engineer EMAIL: g...@snapgear.com > SnapGear Group, McAfee PHONE: +61 7 3435 2888 > 8 Gardner Close FAX: +61 7 3217 5323 > Milton, QLD, 4064, Australia WEB: http://www.SnapGear.com Larry Baker US Geological Survey 650-329-5608 ba...@usgs.gov
_______________________________________________ uClinux-dev mailing list uClinux-dev@uclinux.org http://mailman.uclinux.org/mailman/listinfo/uclinux-dev This message was resent by uclinux-dev@uclinux.org To unsubscribe see: http://mailman.uclinux.org/mailman/options/uclinux-dev