@@ -42,6 +42,28 @@ static inline int stack_map_data_size(struct bpf_map *map)
4242 sizeof (struct bpf_stack_build_id ) : sizeof (u64 );
4343}
4444
45+ /**
46+ * stack_map_calculate_max_depth - Calculate maximum allowed stack trace depth
47+ * @size: Size of the buffer/map value in bytes
48+ * @elem_size: Size of each stack trace element
49+ * @flags: BPF stack trace flags (BPF_F_USER_STACK, BPF_F_USER_BUILD_ID, ...)
50+ *
51+ * Return: Maximum number of stack trace entries that can be safely stored
52+ */
53+ static u32 stack_map_calculate_max_depth (u32 size , u32 elem_size , u64 flags )
54+ {
55+ u32 skip = flags & BPF_F_SKIP_FIELD_MASK ;
56+ u32 max_depth ;
57+ u32 curr_sysctl_max_stack = READ_ONCE (sysctl_perf_event_max_stack );
58+
59+ max_depth = size / elem_size ;
60+ max_depth += skip ;
61+ if (max_depth > curr_sysctl_max_stack )
62+ return curr_sysctl_max_stack ;
63+
64+ return max_depth ;
65+ }
66+
4567static int prealloc_elems_and_freelist (struct bpf_stack_map * smap )
4668{
4769 u64 elem_size = sizeof (struct stack_map_bucket ) +
@@ -300,20 +322,17 @@ static long __bpf_get_stackid(struct bpf_map *map,
300322BPF_CALL_3 (bpf_get_stackid , struct pt_regs * , regs , struct bpf_map * , map ,
301323 u64 , flags )
302324{
303- u32 max_depth = map -> value_size / stack_map_data_size (map );
304- u32 skip = flags & BPF_F_SKIP_FIELD_MASK ;
325+ u32 elem_size = stack_map_data_size (map );
305326 bool user = flags & BPF_F_USER_STACK ;
306327 struct perf_callchain_entry * trace ;
307328 bool kernel = !user ;
329+ u32 max_depth ;
308330
309331 if (unlikely (flags & ~(BPF_F_SKIP_FIELD_MASK | BPF_F_USER_STACK |
310332 BPF_F_FAST_STACK_CMP | BPF_F_REUSE_STACKID )))
311333 return - EINVAL ;
312334
313- max_depth += skip ;
314- if (max_depth > sysctl_perf_event_max_stack )
315- max_depth = sysctl_perf_event_max_stack ;
316-
335+ max_depth = stack_map_calculate_max_depth (map -> value_size , elem_size , flags );
317336 trace = get_perf_callchain (regs , kernel , user , max_depth ,
318337 false, false);
319338
@@ -406,7 +425,7 @@ static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task,
406425 struct perf_callchain_entry * trace_in ,
407426 void * buf , u32 size , u64 flags , bool may_fault )
408427{
409- u32 trace_nr , copy_len , elem_size , num_elem , max_depth ;
428+ u32 trace_nr , copy_len , elem_size , max_depth ;
410429 bool user_build_id = flags & BPF_F_USER_BUILD_ID ;
411430 bool crosstask = task && task != current ;
412431 u32 skip = flags & BPF_F_SKIP_FIELD_MASK ;
@@ -438,21 +457,20 @@ static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task,
438457 goto clear ;
439458 }
440459
441- num_elem = size / elem_size ;
442- max_depth = num_elem + skip ;
443- if (sysctl_perf_event_max_stack < max_depth )
444- max_depth = sysctl_perf_event_max_stack ;
460+ max_depth = stack_map_calculate_max_depth (size , elem_size , flags );
445461
446462 if (may_fault )
447463 rcu_read_lock (); /* need RCU for perf's callchain below */
448464
449- if (trace_in )
465+ if (trace_in ) {
450466 trace = trace_in ;
451- else if (kernel && task )
467+ trace -> nr = min_t (u32 , trace -> nr , max_depth );
468+ } else if (kernel && task ) {
452469 trace = get_callchain_entry_for_task (task , max_depth );
453- else
470+ } else {
454471 trace = get_perf_callchain (regs , kernel , user , max_depth ,
455472 crosstask , false);
473+ }
456474
457475 if (unlikely (!trace ) || trace -> nr < skip ) {
458476 if (may_fault )
@@ -461,7 +479,6 @@ static long __bpf_get_stack(struct pt_regs *regs, struct task_struct *task,
461479 }
462480
463481 trace_nr = trace -> nr - skip ;
464- trace_nr = (trace_nr <= num_elem ) ? trace_nr : num_elem ;
465482 copy_len = trace_nr * elem_size ;
466483
467484 ips = trace -> ip + skip ;
0 commit comments