From: JP Abgrall <jpa@google.com>
Date: Wed, 31 Aug 2011 20:50:15 +0000 (-0700)
Subject: netfilter: qtaguid: fix proc/.../stats uid filtered output
X-Git-Tag: firefly_0821_release~7613^2~328
X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=64753a4df63a211c52a40e4cdf6632e73f2a235d;p=firefly-linux-kernel-4.4.55.git

netfilter: qtaguid: fix proc/.../stats uid filtered output

"cat /proc/net/xt_qtaguid/stats"
for a non-priviledged UID would output multiple twice its own stats.
The fix tweaks the way lines are counted.

Non-root:
  idx iface acct_tag_hex uid_tag_int cnt_set ...
  2 wlan0 0x0 10022 0 ...
  3 wlan0 0x0 10022 1 ...
  4 wlan0 0x3010000000000000 10022 0 ...
  5 wlan0 0x3010000000000000 10022 1 ...

Root:
  idx iface acct_tag_hex uid_tag_int cnt_set
  2 wlan0 0x0 0 0 ...
  3 wlan0 0x0 0 1 ...
  4 wlan0 0x0 1000 0 ...
  ...
  12 wlan0 0x0 10022 0 ...
  13 wlan0 0x0 10022 1 ...
  ...
  18 wlan0 0x3010000000000000 10022 0 ...
  19 wlan0 0x3010000000000000 10022 1 ...

Change-Id: I3cae1f4fee616bc897831350374656b0c718c45b
Signed-off-by: JP Abgrall <jpa@google.com>
---

diff --git a/net/netfilter/xt_qtaguid.c b/net/netfilter/xt_qtaguid.c
index 80b5990045bc..b145f5a4b45d 100644
--- a/net/netfilter/xt_qtaguid.c
+++ b/net/netfilter/xt_qtaguid.c
@@ -1788,6 +1788,7 @@ struct proc_print_info {
 	struct iface_stat *iface_entry;
 	struct tag_stat *ts_entry;
 	int item_index;
+	int items_to_skip;
 	int char_count;
 };
 
@@ -1795,7 +1796,10 @@ static int pp_stats_line(struct proc_print_info *ppi, int cnt_set)
 {
 	int len;
 	struct data_counters *cnts;
+
 	if (!ppi->item_index) {
+		if (ppi->item_index++ < ppi->items_to_skip)
+			return 0;
 		len = snprintf(ppi->outp, ppi->char_count,
 			       "idx iface acct_tag_hex uid_tag_int cnt_set "
 			       "rx_bytes rx_packets "
@@ -1809,6 +1813,7 @@ static int pp_stats_line(struct proc_print_info *ppi, int cnt_set)
 	} else {
 		tag_t tag = ppi->ts_entry->tn.tag;
 		uid_t stat_uid = get_uid_from_tag(tag);
+
 		if (!can_read_other_uid_stats(stat_uid)) {
 			CT_DEBUG("qtaguid: stats line: "
 				 "%s 0x%llx %u: "
@@ -1818,6 +1823,8 @@ static int pp_stats_line(struct proc_print_info *ppi, int cnt_set)
 				 current->pid, current_fsuid());
 			return 0;
 		}
+		if (ppi->item_index++ < ppi->items_to_skip)
+			return 0;
 		cnts = &ppi->ts_entry->counters;
 		len = snprintf(
 			ppi->outp, ppi->char_count,
@@ -1891,11 +1898,13 @@ static int qtaguid_stats_proc_read(char *page, char **num_items_returned,
 	ppi.item_index = 0;
 	ppi.char_count = char_count;
 	ppi.num_items_returned = num_items_returned;
+	ppi.items_to_skip = items_to_skip;
 
 	if (unlikely(module_passive)) {
 		len = pp_stats_line(&ppi, 0);
 		/* The header should always be shorter than the buffer. */
 		WARN_ON(len >= ppi.char_count);
+		(*num_items_returned)++;
 		*eof = 1;
 		return len;
 	}
@@ -1907,16 +1916,17 @@ static int qtaguid_stats_proc_read(char *page, char **num_items_returned,
 	if (*eof)
 		return 0;
 
-	if (!items_to_skip) {
-		/* The idx is there to help debug when things go belly up. */
-		len = pp_stats_line(&ppi, 0);
-		/* Don't advance the outp unless the whole line was printed */
-		if (len >= ppi.char_count) {
-			*ppi.outp = '\0';
-			return ppi.outp - page;
-		}
+	/* The idx is there to help debug when things go belly up. */
+	len = pp_stats_line(&ppi, 0);
+	/* Don't advance the outp unless the whole line was printed */
+	if (len >= ppi.char_count) {
+		*ppi.outp = '\0';
+		return ppi.outp - page;
+	}
+	if (len) {
 		ppi.outp += len;
 		ppi.char_count -= len;
+		(*num_items_returned)++;
 	}
 
 	spin_lock_bh(&iface_stat_list_lock);
@@ -1927,8 +1937,6 @@ static int qtaguid_stats_proc_read(char *page, char **num_items_returned,
 		     node;
 		     node = rb_next(node)) {
 			ppi.ts_entry = rb_entry(node, struct tag_stat, tn.node);
-			if (ppi.item_index++ < items_to_skip)
-				continue;
 			if (!pp_sets(&ppi)) {
 				spin_unlock_bh(
 					&ppi.iface_entry->tag_stat_list_lock);