• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Pretty printing Support for iptables xt_qtaguid module.
3  *
4  * (C) 2011 Google, Inc
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  */
10 
11 /*
12  * Most of the functions in this file just waste time if DEBUG is not defined.
13  * The matching xt_qtaguid_print.h will static inline empty funcs if the needed
14  * debug flags ore not defined.
15  * Those funcs that fail to allocate memory will panic as there is no need to
16  * hobble allong just pretending to do the requested work.
17  */
18 
19 #define DEBUG
20 
21 #include <linux/fs.h>
22 #include <linux/gfp.h>
23 #include <linux/net.h>
24 #include <linux/rbtree.h>
25 #include <linux/slab.h>
26 #include <linux/spinlock_types.h>
27 #include <net/sock.h>
28 
29 #include "xt_qtaguid_internal.h"
30 #include "xt_qtaguid_print.h"
31 
32 #ifdef DDEBUG
33 
_bug_on_err_or_null(void * ptr)34 static void _bug_on_err_or_null(void *ptr)
35 {
36 	if (IS_ERR_OR_NULL(ptr)) {
37 		pr_err("qtaguid: kmalloc failed\n");
38 		BUG();
39 	}
40 }
41 
pp_tag_t(tag_t * tag)42 char *pp_tag_t(tag_t *tag)
43 {
44 	char *res;
45 
46 	if (!tag)
47 		res = kasprintf(GFP_ATOMIC, "tag_t@null{}");
48 	else
49 		res = kasprintf(GFP_ATOMIC,
50 				"tag_t@%p{tag=0x%llx, uid=%u}",
51 				tag, *tag, get_uid_from_tag(*tag));
52 	_bug_on_err_or_null(res);
53 	return res;
54 }
55 
pp_data_counters(struct data_counters * dc,bool showValues)56 char *pp_data_counters(struct data_counters *dc, bool showValues)
57 {
58 	char *res;
59 
60 	if (!dc)
61 		res = kasprintf(GFP_ATOMIC, "data_counters@null{}");
62 	else if (showValues)
63 		res = kasprintf(
64 			GFP_ATOMIC, "data_counters@%p{"
65 			"set0{"
66 			"rx{"
67 			"tcp{b=%llu, p=%llu}, "
68 			"udp{b=%llu, p=%llu},"
69 			"other{b=%llu, p=%llu}}, "
70 			"tx{"
71 			"tcp{b=%llu, p=%llu}, "
72 			"udp{b=%llu, p=%llu},"
73 			"other{b=%llu, p=%llu}}}, "
74 			"set1{"
75 			"rx{"
76 			"tcp{b=%llu, p=%llu}, "
77 			"udp{b=%llu, p=%llu},"
78 			"other{b=%llu, p=%llu}}, "
79 			"tx{"
80 			"tcp{b=%llu, p=%llu}, "
81 			"udp{b=%llu, p=%llu},"
82 			"other{b=%llu, p=%llu}}}}",
83 			dc,
84 			dc->bpc[0][IFS_RX][IFS_TCP].bytes,
85 			dc->bpc[0][IFS_RX][IFS_TCP].packets,
86 			dc->bpc[0][IFS_RX][IFS_UDP].bytes,
87 			dc->bpc[0][IFS_RX][IFS_UDP].packets,
88 			dc->bpc[0][IFS_RX][IFS_PROTO_OTHER].bytes,
89 			dc->bpc[0][IFS_RX][IFS_PROTO_OTHER].packets,
90 			dc->bpc[0][IFS_TX][IFS_TCP].bytes,
91 			dc->bpc[0][IFS_TX][IFS_TCP].packets,
92 			dc->bpc[0][IFS_TX][IFS_UDP].bytes,
93 			dc->bpc[0][IFS_TX][IFS_UDP].packets,
94 			dc->bpc[0][IFS_TX][IFS_PROTO_OTHER].bytes,
95 			dc->bpc[0][IFS_TX][IFS_PROTO_OTHER].packets,
96 			dc->bpc[1][IFS_RX][IFS_TCP].bytes,
97 			dc->bpc[1][IFS_RX][IFS_TCP].packets,
98 			dc->bpc[1][IFS_RX][IFS_UDP].bytes,
99 			dc->bpc[1][IFS_RX][IFS_UDP].packets,
100 			dc->bpc[1][IFS_RX][IFS_PROTO_OTHER].bytes,
101 			dc->bpc[1][IFS_RX][IFS_PROTO_OTHER].packets,
102 			dc->bpc[1][IFS_TX][IFS_TCP].bytes,
103 			dc->bpc[1][IFS_TX][IFS_TCP].packets,
104 			dc->bpc[1][IFS_TX][IFS_UDP].bytes,
105 			dc->bpc[1][IFS_TX][IFS_UDP].packets,
106 			dc->bpc[1][IFS_TX][IFS_PROTO_OTHER].bytes,
107 			dc->bpc[1][IFS_TX][IFS_PROTO_OTHER].packets);
108 	else
109 		res = kasprintf(GFP_ATOMIC, "data_counters@%p{...}", dc);
110 	_bug_on_err_or_null(res);
111 	return res;
112 }
113 
pp_tag_node(struct tag_node * tn)114 char *pp_tag_node(struct tag_node *tn)
115 {
116 	char *tag_str;
117 	char *res;
118 
119 	if (!tn) {
120 		res = kasprintf(GFP_ATOMIC, "tag_node@null{}");
121 		_bug_on_err_or_null(res);
122 		return res;
123 	}
124 	tag_str = pp_tag_t(&tn->tag);
125 	res = kasprintf(GFP_ATOMIC,
126 			"tag_node@%p{tag=%s}",
127 			tn, tag_str);
128 	_bug_on_err_or_null(res);
129 	kfree(tag_str);
130 	return res;
131 }
132 
pp_tag_ref(struct tag_ref * tr)133 char *pp_tag_ref(struct tag_ref *tr)
134 {
135 	char *tn_str;
136 	char *res;
137 
138 	if (!tr) {
139 		res = kasprintf(GFP_ATOMIC, "tag_ref@null{}");
140 		_bug_on_err_or_null(res);
141 		return res;
142 	}
143 	tn_str = pp_tag_node(&tr->tn);
144 	res = kasprintf(GFP_ATOMIC,
145 			"tag_ref@%p{%s, num_sock_tags=%d}",
146 			tr, tn_str, tr->num_sock_tags);
147 	_bug_on_err_or_null(res);
148 	kfree(tn_str);
149 	return res;
150 }
151 
pp_tag_stat(struct tag_stat * ts)152 char *pp_tag_stat(struct tag_stat *ts)
153 {
154 	char *tn_str;
155 	char *counters_str;
156 	char *parent_counters_str;
157 	char *res;
158 
159 	if (!ts) {
160 		res = kasprintf(GFP_ATOMIC, "tag_stat@null{}");
161 		_bug_on_err_or_null(res);
162 		return res;
163 	}
164 	tn_str = pp_tag_node(&ts->tn);
165 	counters_str = pp_data_counters(&ts->counters, true);
166 	parent_counters_str = pp_data_counters(ts->parent_counters, false);
167 	res = kasprintf(GFP_ATOMIC,
168 			"tag_stat@%p{%s, counters=%s, parent_counters=%s}",
169 			ts, tn_str, counters_str, parent_counters_str);
170 	_bug_on_err_or_null(res);
171 	kfree(tn_str);
172 	kfree(counters_str);
173 	kfree(parent_counters_str);
174 	return res;
175 }
176 
pp_iface_stat(struct iface_stat * is)177 char *pp_iface_stat(struct iface_stat *is)
178 {
179 	char *res;
180 	if (!is) {
181 		res = kasprintf(GFP_ATOMIC, "iface_stat@null{}");
182 	} else {
183 		struct data_counters *cnts = &is->totals_via_skb;
184 		res = kasprintf(GFP_ATOMIC, "iface_stat@%p{"
185 				"list=list_head{...}, "
186 				"ifname=%s, "
187 				"total_dev={rx={bytes=%llu, "
188 				"packets=%llu}, "
189 				"tx={bytes=%llu, "
190 				"packets=%llu}}, "
191 				"total_skb={rx={bytes=%llu, "
192 				"packets=%llu}, "
193 				"tx={bytes=%llu, "
194 				"packets=%llu}}, "
195 				"last_known_valid=%d, "
196 				"last_known={rx={bytes=%llu, "
197 				"packets=%llu}, "
198 				"tx={bytes=%llu, "
199 				"packets=%llu}}, "
200 				"active=%d, "
201 				"net_dev=%p, "
202 				"proc_ptr=%p, "
203 				"tag_stat_tree=rb_root{...}}",
204 				is,
205 				is->ifname,
206 				is->totals_via_dev[IFS_RX].bytes,
207 				is->totals_via_dev[IFS_RX].packets,
208 				is->totals_via_dev[IFS_TX].bytes,
209 				is->totals_via_dev[IFS_TX].packets,
210 				dc_sum_bytes(cnts, 0, IFS_RX),
211 				dc_sum_packets(cnts, 0, IFS_RX),
212 				dc_sum_bytes(cnts, 0, IFS_TX),
213 				dc_sum_packets(cnts, 0, IFS_TX),
214 				is->last_known_valid,
215 				is->last_known[IFS_RX].bytes,
216 				is->last_known[IFS_RX].packets,
217 				is->last_known[IFS_TX].bytes,
218 				is->last_known[IFS_TX].packets,
219 				is->active,
220 				is->net_dev,
221 				is->proc_ptr);
222 	}
223 	_bug_on_err_or_null(res);
224 	return res;
225 }
226 
pp_sock_tag(struct sock_tag * st)227 char *pp_sock_tag(struct sock_tag *st)
228 {
229 	char *tag_str;
230 	char *res;
231 
232 	if (!st) {
233 		res = kasprintf(GFP_ATOMIC, "sock_tag@null{}");
234 		_bug_on_err_or_null(res);
235 		return res;
236 	}
237 	tag_str = pp_tag_t(&st->tag);
238 	res = kasprintf(GFP_ATOMIC, "sock_tag@%p{"
239 			"sock_node=rb_node{...}, "
240 			"sk=%p (f_count=%d), list=list_head{...}, "
241 			"pid=%u, tag=%s}",
242 			st, st->sk, atomic_read(
243 				&st->sk->sk_refcnt),
244 			st->pid, tag_str);
245 	_bug_on_err_or_null(res);
246 	kfree(tag_str);
247 	return res;
248 }
249 
pp_uid_tag_data(struct uid_tag_data * utd)250 char *pp_uid_tag_data(struct uid_tag_data *utd)
251 {
252 	char *res;
253 
254 	if (!utd)
255 		res = kasprintf(GFP_ATOMIC, "uid_tag_data@null{}");
256 	else
257 		res = kasprintf(GFP_ATOMIC, "uid_tag_data@%p{"
258 				"uid=%u, num_active_acct_tags=%d, "
259 				"num_pqd=%d, "
260 				"tag_node_tree=rb_root{...}, "
261 				"proc_qtu_data_tree=rb_root{...}}",
262 				utd, utd->uid,
263 				utd->num_active_tags, utd->num_pqd);
264 	_bug_on_err_or_null(res);
265 	return res;
266 }
267 
pp_proc_qtu_data(struct proc_qtu_data * pqd)268 char *pp_proc_qtu_data(struct proc_qtu_data *pqd)
269 {
270 	char *parent_tag_data_str;
271 	char *res;
272 
273 	if (!pqd) {
274 		res = kasprintf(GFP_ATOMIC, "proc_qtu_data@null{}");
275 		_bug_on_err_or_null(res);
276 		return res;
277 	}
278 	parent_tag_data_str = pp_uid_tag_data(pqd->parent_tag_data);
279 	res = kasprintf(GFP_ATOMIC, "proc_qtu_data@%p{"
280 			"node=rb_node{...}, pid=%u, "
281 			"parent_tag_data=%s, "
282 			"sock_tag_list=list_head{...}}",
283 			pqd, pqd->pid, parent_tag_data_str
284 		);
285 	_bug_on_err_or_null(res);
286 	kfree(parent_tag_data_str);
287 	return res;
288 }
289 
290 /*------------------------------------------*/
prdebug_sock_tag_tree(int indent_level,struct rb_root * sock_tag_tree)291 void prdebug_sock_tag_tree(int indent_level,
292 			   struct rb_root *sock_tag_tree)
293 {
294 	struct rb_node *node;
295 	struct sock_tag *sock_tag_entry;
296 	char *str;
297 
298 	if (!unlikely(qtaguid_debug_mask & DDEBUG_MASK))
299 		return;
300 
301 	if (RB_EMPTY_ROOT(sock_tag_tree)) {
302 		str = "sock_tag_tree=rb_root{}";
303 		pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
304 		return;
305 	}
306 
307 	str = "sock_tag_tree=rb_root{";
308 	pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
309 	indent_level++;
310 	for (node = rb_first(sock_tag_tree);
311 	     node;
312 	     node = rb_next(node)) {
313 		sock_tag_entry = rb_entry(node, struct sock_tag, sock_node);
314 		str = pp_sock_tag(sock_tag_entry);
315 		pr_debug("%*d: %s,\n", indent_level*2, indent_level, str);
316 		kfree(str);
317 	}
318 	indent_level--;
319 	str = "}";
320 	pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
321 }
322 
prdebug_sock_tag_list(int indent_level,struct list_head * sock_tag_list)323 void prdebug_sock_tag_list(int indent_level,
324 			   struct list_head *sock_tag_list)
325 {
326 	struct sock_tag *sock_tag_entry;
327 	char *str;
328 
329 	if (!unlikely(qtaguid_debug_mask & DDEBUG_MASK))
330 		return;
331 
332 	if (list_empty(sock_tag_list)) {
333 		str = "sock_tag_list=list_head{}";
334 		pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
335 		return;
336 	}
337 
338 	str = "sock_tag_list=list_head{";
339 	pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
340 	indent_level++;
341 	list_for_each_entry(sock_tag_entry, sock_tag_list, list) {
342 		str = pp_sock_tag(sock_tag_entry);
343 		pr_debug("%*d: %s,\n", indent_level*2, indent_level, str);
344 		kfree(str);
345 	}
346 	indent_level--;
347 	str = "}";
348 	pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
349 }
350 
prdebug_proc_qtu_data_tree(int indent_level,struct rb_root * proc_qtu_data_tree)351 void prdebug_proc_qtu_data_tree(int indent_level,
352 				struct rb_root *proc_qtu_data_tree)
353 {
354 	char *str;
355 	struct rb_node *node;
356 	struct proc_qtu_data *proc_qtu_data_entry;
357 
358 	if (!unlikely(qtaguid_debug_mask & DDEBUG_MASK))
359 		return;
360 
361 	if (RB_EMPTY_ROOT(proc_qtu_data_tree)) {
362 		str = "proc_qtu_data_tree=rb_root{}";
363 		pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
364 		return;
365 	}
366 
367 	str = "proc_qtu_data_tree=rb_root{";
368 	pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
369 	indent_level++;
370 	for (node = rb_first(proc_qtu_data_tree);
371 	     node;
372 	     node = rb_next(node)) {
373 		proc_qtu_data_entry = rb_entry(node,
374 					       struct proc_qtu_data,
375 					       node);
376 		str = pp_proc_qtu_data(proc_qtu_data_entry);
377 		pr_debug("%*d: %s,\n", indent_level*2, indent_level,
378 			 str);
379 		kfree(str);
380 		indent_level++;
381 		prdebug_sock_tag_list(indent_level,
382 				      &proc_qtu_data_entry->sock_tag_list);
383 		indent_level--;
384 
385 	}
386 	indent_level--;
387 	str = "}";
388 	pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
389 }
390 
prdebug_tag_ref_tree(int indent_level,struct rb_root * tag_ref_tree)391 void prdebug_tag_ref_tree(int indent_level, struct rb_root *tag_ref_tree)
392 {
393 	char *str;
394 	struct rb_node *node;
395 	struct tag_ref *tag_ref_entry;
396 
397 	if (!unlikely(qtaguid_debug_mask & DDEBUG_MASK))
398 		return;
399 
400 	if (RB_EMPTY_ROOT(tag_ref_tree)) {
401 		str = "tag_ref_tree{}";
402 		pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
403 		return;
404 	}
405 
406 	str = "tag_ref_tree{";
407 	pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
408 	indent_level++;
409 	for (node = rb_first(tag_ref_tree);
410 	     node;
411 	     node = rb_next(node)) {
412 		tag_ref_entry = rb_entry(node,
413 					 struct tag_ref,
414 					 tn.node);
415 		str = pp_tag_ref(tag_ref_entry);
416 		pr_debug("%*d: %s,\n", indent_level*2, indent_level,
417 			 str);
418 		kfree(str);
419 	}
420 	indent_level--;
421 	str = "}";
422 	pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
423 }
424 
prdebug_uid_tag_data_tree(int indent_level,struct rb_root * uid_tag_data_tree)425 void prdebug_uid_tag_data_tree(int indent_level,
426 			       struct rb_root *uid_tag_data_tree)
427 {
428 	char *str;
429 	struct rb_node *node;
430 	struct uid_tag_data *uid_tag_data_entry;
431 
432 	if (!unlikely(qtaguid_debug_mask & DDEBUG_MASK))
433 		return;
434 
435 	if (RB_EMPTY_ROOT(uid_tag_data_tree)) {
436 		str = "uid_tag_data_tree=rb_root{}";
437 		pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
438 		return;
439 	}
440 
441 	str = "uid_tag_data_tree=rb_root{";
442 	pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
443 	indent_level++;
444 	for (node = rb_first(uid_tag_data_tree);
445 	     node;
446 	     node = rb_next(node)) {
447 		uid_tag_data_entry = rb_entry(node, struct uid_tag_data,
448 					      node);
449 		str = pp_uid_tag_data(uid_tag_data_entry);
450 		pr_debug("%*d: %s,\n", indent_level*2, indent_level, str);
451 		kfree(str);
452 		if (!RB_EMPTY_ROOT(&uid_tag_data_entry->tag_ref_tree)) {
453 			indent_level++;
454 			prdebug_tag_ref_tree(indent_level,
455 					     &uid_tag_data_entry->tag_ref_tree);
456 			indent_level--;
457 		}
458 	}
459 	indent_level--;
460 	str = "}";
461 	pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
462 }
463 
prdebug_tag_stat_tree(int indent_level,struct rb_root * tag_stat_tree)464 void prdebug_tag_stat_tree(int indent_level,
465 				  struct rb_root *tag_stat_tree)
466 {
467 	char *str;
468 	struct rb_node *node;
469 	struct tag_stat *ts_entry;
470 
471 	if (!unlikely(qtaguid_debug_mask & DDEBUG_MASK))
472 		return;
473 
474 	if (RB_EMPTY_ROOT(tag_stat_tree)) {
475 		str = "tag_stat_tree{}";
476 		pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
477 		return;
478 	}
479 
480 	str = "tag_stat_tree{";
481 	pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
482 	indent_level++;
483 	for (node = rb_first(tag_stat_tree);
484 	     node;
485 	     node = rb_next(node)) {
486 		ts_entry = rb_entry(node, struct tag_stat, tn.node);
487 		str = pp_tag_stat(ts_entry);
488 		pr_debug("%*d: %s\n", indent_level*2, indent_level,
489 			 str);
490 		kfree(str);
491 	}
492 	indent_level--;
493 	str = "}";
494 	pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
495 }
496 
prdebug_iface_stat_list(int indent_level,struct list_head * iface_stat_list)497 void prdebug_iface_stat_list(int indent_level,
498 			     struct list_head *iface_stat_list)
499 {
500 	char *str;
501 	struct iface_stat *iface_entry;
502 
503 	if (!unlikely(qtaguid_debug_mask & DDEBUG_MASK))
504 		return;
505 
506 	if (list_empty(iface_stat_list)) {
507 		str = "iface_stat_list=list_head{}";
508 		pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
509 		return;
510 	}
511 
512 	str = "iface_stat_list=list_head{";
513 	pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
514 	indent_level++;
515 	list_for_each_entry(iface_entry, iface_stat_list, list) {
516 		str = pp_iface_stat(iface_entry);
517 		pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
518 		kfree(str);
519 
520 		spin_lock_bh(&iface_entry->tag_stat_list_lock);
521 		if (!RB_EMPTY_ROOT(&iface_entry->tag_stat_tree)) {
522 			indent_level++;
523 			prdebug_tag_stat_tree(indent_level,
524 					      &iface_entry->tag_stat_tree);
525 			indent_level--;
526 		}
527 		spin_unlock_bh(&iface_entry->tag_stat_list_lock);
528 	}
529 	indent_level--;
530 	str = "}";
531 	pr_debug("%*d: %s\n", indent_level*2, indent_level, str);
532 }
533 
534 #endif  /* ifdef DDEBUG */
535 /*------------------------------------------*/
536 static const char * const netdev_event_strings[] = {
537 	"netdev_unknown",
538 	"NETDEV_UP",
539 	"NETDEV_DOWN",
540 	"NETDEV_REBOOT",
541 	"NETDEV_CHANGE",
542 	"NETDEV_REGISTER",
543 	"NETDEV_UNREGISTER",
544 	"NETDEV_CHANGEMTU",
545 	"NETDEV_CHANGEADDR",
546 	"NETDEV_GOING_DOWN",
547 	"NETDEV_CHANGENAME",
548 	"NETDEV_FEAT_CHANGE",
549 	"NETDEV_BONDING_FAILOVER",
550 	"NETDEV_PRE_UP",
551 	"NETDEV_PRE_TYPE_CHANGE",
552 	"NETDEV_POST_TYPE_CHANGE",
553 	"NETDEV_POST_INIT",
554 	"NETDEV_UNREGISTER_BATCH",
555 	"NETDEV_RELEASE",
556 	"NETDEV_NOTIFY_PEERS",
557 	"NETDEV_JOIN",
558 };
559 
netdev_evt_str(int netdev_event)560 const char *netdev_evt_str(int netdev_event)
561 {
562 	if (netdev_event < 0
563 	    || netdev_event >= ARRAY_SIZE(netdev_event_strings))
564 		return "bad event num";
565 	return netdev_event_strings[netdev_event];
566 }
567