• Steven Rostedt (Google)'s avatar
    tracing: Stop FORTIFY_SOURCE complaining about stack trace caller · bec3c25c
    Steven Rostedt (Google) authored
    The stack_trace event is an event created by the tracing subsystem to
    store stack traces. It originally just contained a hard coded array of 8
    words to hold the stack, and a "size" to know how many entries are there.
    This is exported to user space as:
    
    name: kernel_stack
    ID: 4
    format:
    	field:unsigned short common_type;	offset:0;	size:2;	signed:0;
    	field:unsigned char common_flags;	offset:2;	size:1;	signed:0;
    	field:unsigned char common_preempt_count;	offset:3;	size:1;	signed:0;
    	field:int common_pid;	offset:4;	size:4;	signed:1;
    
    	field:int size;	offset:8;	size:4;	signed:1;
    	field:unsigned long caller[8];	offset:16;	size:64;	signed:0;
    
    print fmt: "\t=> %ps\n\t=> %ps\n\t=> %ps\n" "\t=> %ps\n\t=> %ps\n\t=> %ps\n" "\t=> %ps\n\t=> %ps\n",i
     (void *)REC->caller[0], (void *)REC->caller[1], (void *)REC->caller[2],
     (void *)REC->caller[3], (void *)REC->caller[4], (void *)REC->caller[5],
     (void *)REC->caller[6], (void *)REC->caller[7]
    
    Where the user space tracers could parse the stack. The library was
    updated for this specific event to only look at the size, and not the
    array. But some older users still look at the array (note, the older code
    still checks to make sure the array fits inside the event that it read.
    That is, if only 4 words were saved, the parser would not read the fifth
    word because it will see that it was outside of the event size).
    
    This event was changed a while ago to be more dynamic, and would save a
    full stack even if it was greater than 8 words. It does this by simply
    allocating more ring buffer to hold the extra words. Then it copies in the
    stack via:
    
    	memcpy(&entry->caller, fstack->calls, size);
    
    As the entry is struct stack_entry, that is created by a macro to both
    create the structure and export this to user space, it still had the caller
    field of entry defined as: unsigned long caller[8].
    
    When the stack is greater than 8, the FORTIFY_SOURCE code notices that the
    amount being copied is greater than the source array and complains about
    it. It has no idea that the source is pointing to the ring buffer with the
    required allocation.
    
    To hide this from the FORTIFY_SOURCE logic, pointer arithmetic is used:
    
    	ptr = ring_buffer_event_data(event);
    	entry = ptr;
    	ptr += offsetof(typeof(*entry), caller);
    	memcpy(ptr, fstack->calls, size);
    
    Link: https://lore.kernel.org/all/20230612160748.4082850-1-svens@linux.ibm.com/
    Link: https://lore.kernel.org/linux-trace-kernel/20230712105235.5fc441aa@gandalf.local.home
    
    Cc: Masami Hiramatsu <mhiramat@kernel.org>
    Cc: Mark Rutland <mark.rutland@arm.com>
    Reported-by: default avatarSven Schnelle <svens@linux.ibm.com>
    Tested-by: default avatarSven Schnelle <svens@linux.ibm.com>
    Signed-off-by: default avatarSteven Rostedt (Google) <rostedt@goodmis.org>
    bec3c25c
trace.c 257 KB