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

Reply via email to