Skip to content

Commit bec3c25

Browse files
committed
tracing: Stop FORTIFY_SOURCE complaining about stack trace caller
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/[email protected]/ Link: https://lore.kernel.org/linux-trace-kernel/[email protected] Cc: Masami Hiramatsu <[email protected]> Cc: Mark Rutland <[email protected]> Reported-by: Sven Schnelle <[email protected]> Tested-by: Sven Schnelle <[email protected]> Signed-off-by: Steven Rostedt (Google) <[email protected]>
1 parent 26efd79 commit bec3c25

File tree

1 file changed

+19
-2
lines changed

1 file changed

+19
-2
lines changed

kernel/trace/trace.c

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3118,6 +3118,7 @@ static void __ftrace_trace_stack(struct trace_buffer *buffer,
31183118
struct ftrace_stack *fstack;
31193119
struct stack_entry *entry;
31203120
int stackidx;
3121+
void *ptr;
31213122

31223123
/*
31233124
* Add one, for this function and the call to save_stack_trace()
@@ -3161,9 +3162,25 @@ static void __ftrace_trace_stack(struct trace_buffer *buffer,
31613162
trace_ctx);
31623163
if (!event)
31633164
goto out;
3164-
entry = ring_buffer_event_data(event);
3165+
ptr = ring_buffer_event_data(event);
3166+
entry = ptr;
3167+
3168+
/*
3169+
* For backward compatibility reasons, the entry->caller is an
3170+
* array of 8 slots to store the stack. This is also exported
3171+
* to user space. The amount allocated on the ring buffer actually
3172+
* holds enough for the stack specified by nr_entries. This will
3173+
* go into the location of entry->caller. Due to string fortifiers
3174+
* checking the size of the destination of memcpy() it triggers
3175+
* when it detects that size is greater than 8. To hide this from
3176+
* the fortifiers, we use "ptr" and pointer arithmetic to assign caller.
3177+
*
3178+
* The below is really just:
3179+
* memcpy(&entry->caller, fstack->calls, size);
3180+
*/
3181+
ptr += offsetof(typeof(*entry), caller);
3182+
memcpy(ptr, fstack->calls, size);
31653183

3166-
memcpy(&entry->caller, fstack->calls, size);
31673184
entry->size = nr_entries;
31683185

31693186
if (!call_filter_check_discard(call, entry, buffer, event))

0 commit comments

Comments
 (0)