blob: 4cf62e33b7e1f5e2bb2970ea81b13d9de73ac59f [file] [log] [blame]
Googlerb48fa912023-03-17 12:40:29 +05301/*
2 * Copyright (c) 2015-2016, 2020 The Linux Foundation. All rights reserved.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include <asm/stacktrace.h>
18#include <asm/current.h>
19#include <linux/sched.h>
20#include <linux/module.h>
21#include <linux/smp.h>
22
23#include "skbuff_debug.h"
24#include "skbuff_notifier.h"
25#include "skbuff_recycle.h"
26
27static int skbuff_debugobj_enabled __read_mostly = 1;
28
29static int skbuff_debug_event_handler(struct notifier_block *nb,
30 unsigned long action, void *data);
31static struct notifier_block skbuff_debug_notify = {
32 .notifier_call = skbuff_debug_event_handler,
33 .priority = 0
34};
35
36inline u32 skbuff_debugobj_sum(struct sk_buff *skb)
37{
38 int pos = offsetof(struct sk_buff, free_addr);
39 u32 sum = 0;
40
41 while (pos--)
42 sum += ((u8 *)skb)[pos];
43
44 return sum;
45}
46
47struct skbuff_debugobj_walking {
48 int pos;
49 void **d;
50};
51
52static int skbuff_debugobj_walkstack(struct stackframe *frame, void *p)
53{
54 struct skbuff_debugobj_walking *w = (struct skbuff_debugobj_walking *)p;
55 unsigned long pc = frame->pc;
56
57 if (w->pos < DEBUG_OBJECTS_SKBUFF_STACKSIZE - 1) {
58 w->d[w->pos++] = (void *)pc;
59 return 0;
60 }
61
62 return -ENOENT;
63}
64
65#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
66static void skbuff_debugobj_get_stack(void **ret)
67{
68 struct stackframe frame;
69
70 register unsigned long current_sp asm ("sp");
71 struct skbuff_debugobj_walking w = {0, ret};
72 void *p = &w;
73
74#ifdef CONFIG_ARM
75 frame.fp = (unsigned long)__builtin_frame_address(0);
76 frame.lr = (unsigned long)__builtin_return_address(0);
77 frame.sp = current_sp;
78 frame.pc = (unsigned long)skbuff_debugobj_get_stack;
79#endif
80
81#ifdef CONFIG_ARM64
82 start_backtrace(&frame, (unsigned long)__builtin_frame_address(0), (unsigned long)skbuff_debugobj_get_stack);
83 walk_stackframe(current, &frame, skbuff_debugobj_walkstack, p);
84#else
85 walk_stackframe(&frame, skbuff_debugobj_walkstack, p);
86#endif
87 ret[w.pos] = NULL;
88}
89#else
90#error
91static void skbuff_debugobj_get_stack(void **ret)
92{
93 /* not supported */
94 ret[0] = 0xdeadbeef;
95}
96#endif
97
98void skbuff_debugobj_print_stack(void *const *stack)
99{
100 int i;
101
102 for (i = 0; stack[i]; i++)
103 pr_emerg("\t %pS (0x%p)\n", stack[i], stack[i]);
104}
105
106static const char *skbuff_debugobj_state_name(const struct sk_buff *skb)
107{
108 int obj_state;
109
110 obj_state = debug_object_get_state((struct sk_buff *)skb);
111 switch (obj_state) {
112 case ODEBUG_STATE_NONE:
113 return "none";
114 case ODEBUG_STATE_INIT:
115 return "init";
116 case ODEBUG_STATE_INACTIVE:
117 return "inactive";
118 case ODEBUG_STATE_ACTIVE:
119 return "active";
120 case ODEBUG_STATE_DESTROYED:
121 return "destroyed";
122 case ODEBUG_STATE_NOTAVAILABLE:
123 return "not available";
124 default:
125 return "invalid";
126 }
127}
128
129void skbuff_debugobj_print_skb(const struct sk_buff *skb)
130{
131 pr_emerg("skb_debug: current process = %s (pid %i)\n",
132 current->comm, current->pid);
133 pr_emerg("skb_debug: skb 0x%p, next 0x%p, prev 0x%p, state = %s\n", skb,
134 skb->next, skb->prev, skbuff_debugobj_state_name(skb));
135 pr_emerg("skb_debug: free stack:\n");
136 skbuff_debugobj_print_stack(skb->free_addr);
137 pr_emerg("skb_debug: alloc stack:\n");
138 skbuff_debugobj_print_stack(skb->alloc_addr);
139}
140EXPORT_SYMBOL(skbuff_debugobj_print_skb);
141
142/* skbuff_debugobj_fixup():
143 * Called when an error is detected in the state machine for
144 * the objects
145 */
146static bool skbuff_debugobj_fixup(void *addr, enum debug_obj_state state)
147{
148 struct sk_buff *skb = (struct sk_buff *)addr;
149 ftrace_dump(DUMP_ALL);
150 WARN(1, "skb_debug: state = %d, skb = 0x%p sum = %d (now %d)\n",
151 state, skb, skb->sum, skbuff_debugobj_sum(skb));
152 skb_recycler_notifier_send_event(SKB_RECYCLER_NOTIFIER_FSM, skb);
153
154 return true;
155}
156
157static struct debug_obj_descr skbuff_debug_descr = {
158 .name = "sk_buff_struct",
159 .fixup_init = skbuff_debugobj_fixup,
160 .fixup_activate = skbuff_debugobj_fixup,
161 .fixup_destroy = skbuff_debugobj_fixup,
162 .fixup_free = skbuff_debugobj_fixup,
163};
164
165inline void skbuff_debugobj_activate(struct sk_buff *skb)
166{
167 int ret = 0;
168
169 if (!skbuff_debugobj_enabled)
170 return;
171
172 skbuff_debugobj_get_stack(skb->alloc_addr);
173 ret = debug_object_activate(skb, &skbuff_debug_descr);
174 if (ret)
175 goto err_act;
176
177 skbuff_debugobj_sum_validate(skb);
178
179 return;
180
181err_act:
182 ftrace_dump(DUMP_ALL);
183 WARN(1, "skb_debug: failed to activate err = %d skb = 0x%p sum = %d (now %d)\n",
184 ret, skb, skb->sum, skbuff_debugobj_sum(skb));
185 skb_recycler_notifier_send_event(SKB_RECYCLER_NOTIFIER_DBLALLOC, skb);
186}
187
188inline void skbuff_debugobj_init_and_activate(struct sk_buff *skb)
189{
190 if (!skbuff_debugobj_enabled)
191 return;
192
193 /* if we're coming from the slab, the skb->sum might
194 * be invalid anyways
195 */
196 skb->sum = skbuff_debugobj_sum(skb);
197
198 debug_object_init(skb, &skbuff_debug_descr);
199 skbuff_debugobj_activate(skb);
200}
201
202inline void skbuff_debugobj_deactivate(struct sk_buff *skb)
203{
204 int obj_state;
205
206 if (!skbuff_debugobj_enabled)
207 return;
208
209 skb->sum = skbuff_debugobj_sum(skb);
210
211 obj_state = debug_object_get_state(skb);
212
213 if (obj_state == ODEBUG_STATE_ACTIVE) {
214 debug_object_deactivate(skb, &skbuff_debug_descr);
215 skbuff_debugobj_get_stack(skb->free_addr);
216 return;
217 }
218
219 ftrace_dump(DUMP_ALL);
220 WARN(1, "skb_debug: deactivating inactive object skb=0x%p state=%d sum = %d (now %d)\n",
221 skb, obj_state, skb->sum, skbuff_debugobj_sum(skb));
222 skb_recycler_notifier_send_event(SKB_RECYCLER_NOTIFIER_DBLFREE, skb);
223}
224
225inline void _skbuff_debugobj_sum_validate(struct sk_buff *skb,
226 const char *var, const char *src,
227 int line, const char *fxn)
228{
229 if (!skbuff_debugobj_enabled || !skb)
230 return;
231
232 if (skb->sum == skbuff_debugobj_sum(skb))
233 return;
234
235 ftrace_dump(DUMP_ALL);
236 WARN(1, "skb_debug: skb sum changed skb = 0x%p sum = %d (now %d)\n",
237 skb, skb->sum, skbuff_debugobj_sum(skb));
238 pr_emerg("skb_debug: %s() checking %s in %s:%d\n", fxn, var, src, line);
239 skb_recycler_notifier_send_event(SKB_RECYCLER_NOTIFIER_SUMERR, skb);
240}
241
242inline void skbuff_debugobj_sum_update(struct sk_buff *skb)
243{
244 if (!skbuff_debugobj_enabled || !skb)
245 return;
246
247 skb->sum = skbuff_debugobj_sum(skb);
248}
249
250inline void skbuff_debugobj_destroy(struct sk_buff *skb)
251{
252 if (!skbuff_debugobj_enabled)
253 return;
254
255 debug_object_destroy(skb, &skbuff_debug_descr);
256}
257
258static int __init disable_object_debug(char *str)
259{
260 skbuff_debugobj_enabled = 0;
261
262 pr_info("skb_debug: debug objects is disabled\n");
263 return 0;
264}
265
266early_param("no_skbuff_debug_objects", disable_object_debug);
267
268void skbuff_debugobj_print_skb_list(const struct sk_buff *skb_list,
269 const char *list_title, int cpu)
270{
271 int count;
272 struct sk_buff *skb_i = (struct sk_buff *)skb_list;
273 u32 sum_i, sum_now;
274 int obj_state;
275
276 if (cpu < 0) {
277 cpu = get_cpu();
278 put_cpu();
279 }
280 pr_emerg("skb_debug: start skb list '%s' [CPU#%d]\n", list_title, cpu);
281 count = 0;
282 if (skb_list) {
283 do {
284 obj_state =
285 debug_object_get_state(skb_i);
286 if (obj_state < ODEBUG_STATE_NOTAVAILABLE) {
287 sum_i = skb_i->sum;
288 sum_now = skbuff_debugobj_sum(skb_i);
289 } else {
290 sum_i = 0;
291 sum_now = 0;
292 }
293 if (sum_i != sum_now) {
294 pr_emerg("skb_debug: [%02d] skb 0x%p, next 0x%p, prev 0x%p, state %d (%s), sum %d (now %d)\n",
295 count, skb_i, skb_i->next, skb_i->prev,
296 obj_state, skbuff_debugobj_state_name(skb_i),
297 sum_i, sum_now);
298 }
299 skb_i = skb_i->next;
300 count++;
301 } while (skb_list != skb_i);
302 }
303 pr_emerg("skb_debug: end skb list '%s'. In total %d skbs iterated.\n", list_title, count);
304}
305
306void skbuff_debugobj_register_callback(void)
307{
308 skb_recycler_notifier_register(&skbuff_debug_notify);
309}
310
311int skbuff_debug_event_handler(struct notifier_block *nb, unsigned long action,
312 void *data)
313{
314 struct sk_buff *skb = (struct sk_buff *)data;
315
316 pr_emerg("skb_debug: notifier event %lu\n", action);
317 skbuff_debugobj_print_skb(skb);
318 skb_recycler_print_all_lists();
319
320 return NOTIFY_DONE;
321}