Blob Blame History Raw
commit 91136b3b6c9338d506c217e21b7c4a34c0af8671
Author: Frank Ch. Eigler <fche@redhat.com>
Date:   Mon Jan 20 21:43:40 2014 -0500

    RHBZ1055818: correct SEGV in pmda/linux for overlarge icmpmsg type
    
    On linux, /proc/net/snmp | grep IcmpMsg normally contains a few
    ordinal-indexed counters, whose indexes can be larger than than the
    pcp pmda likes.  This could lead to SEGVs or mild memory corruption.
    
    The new code adds an explicit limit check, and bumps up the limits
    to 256 (related to the kernel __ICMPMSG_MIB_MAX) than the misused
    SNMP_PERLINE (which only limits how many different message type
    counters may be listed on the same line - not their ordinal values).

diff --git a/src/pmdas/linux/proc_net_snmp.c b/src/pmdas/linux/proc_net_snmp.c
index 80be988..87ab6fa 100644
--- a/src/pmdas/linux/proc_net_snmp.c
+++ b/src/pmdas/linux/proc_net_snmp.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013 Red Hat.
+ * Copyright (c) 2013-2014 Red Hat.
  * Copyright (c) 2000,2004 Silicon Graphics, Inc.  All Rights Reserved.
  * 
  * This program is free software; you can redistribute it and/or modify it
@@ -249,7 +249,8 @@ get_fields(snmp_fields_t *fields, char *header, char *buffer)
 }
 
 static void
-get_ordinal_fields(snmp_fields_t *fields, char *header, char *buffer)
+get_ordinal_fields(snmp_fields_t *fields, char *header, char *buffer,
+                   unsigned limit)
 {
     int i, j, count;
     unsigned int inst;
@@ -270,6 +271,8 @@ get_ordinal_fields(snmp_fields_t *fields, char *header, char *buffer)
         for (i = 0; fields[i].field; i++) {
             if (sscanf(indices[j], fields[i].field, &inst) != 1)
                 continue;
+            if (inst >= limit)
+                continue;
             *(fields[i].offset + inst) = strtoull(p, NULL, 10);
             break;
 	}
@@ -314,7 +317,7 @@ init_refresh_proc_net_snmp(proc_net_snmp_t *snmp)
     /* only need to allocate and setup the names once */
     if (proc_net_snmp_icmpmsg_names)
 	return;
-    i = SNMP_PERLINE * SNMP_MAX_ICMPMSG_TYPESTR;
+    i = NR_ICMPMSG_COUNTERS * SNMP_MAX_ICMPMSG_TYPESTR;
     proc_net_snmp_icmpmsg_names = malloc(i);
     if (!proc_net_snmp_icmpmsg_names)
 	return;
@@ -326,7 +329,7 @@ init_refresh_proc_net_snmp(proc_net_snmp_t *snmp)
 	s += SNMP_MAX_ICMPMSG_TYPESTR;
     }
     idp = PMDAINDOM(ICMPMSG_INDOM);
-    idp->it_numinst = SNMP_PERLINE;
+    idp->it_numinst = NR_ICMPMSG_COUNTERS;
     idp->it_set = _pm_proc_net_snmp_indom_id;
 }
 
@@ -347,7 +350,8 @@ refresh_proc_net_snmp(proc_net_snmp_t *snmp)
 	    else if (strncmp(values, "Icmp:", 5) == 0)
 		get_fields(icmp_fields, header, values);
 	    else if (strncmp(values, "IcmpMsg:", 8) == 0)
-		get_ordinal_fields(icmpmsg_fields, header, values);
+		get_ordinal_fields(icmpmsg_fields, header, values,
+                                   NR_ICMPMSG_COUNTERS);
 	    else if (strncmp(values, "Tcp:", 4) == 0)
 		get_fields(tcp_fields, header, values);
 	    else if (strncmp(values, "Udp:", 4) == 0)
diff --git a/src/pmdas/linux/proc_net_snmp.h b/src/pmdas/linux/proc_net_snmp.h
index 27e9a68..eeeb2a6 100644
--- a/src/pmdas/linux/proc_net_snmp.h
+++ b/src/pmdas/linux/proc_net_snmp.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013 Red Hat.
+ * Copyright (c) 2013-2014 Red Hat.
  * Copyright (c) 2000,2004 Silicon Graphics, Inc.  All Rights Reserved.
  * 
  * This program is free software; you can redistribute it and/or modify it
@@ -16,7 +16,7 @@
 #define SNMP_MAX_COLUMNS	64	/* arbitrary upper bound */
 #define SNMP_PERLINE		16	/* see net/ipv4/proc.c */
 #define SNMP_MAX_ICMPMSG_TYPESTR 8	/* longest name for type */
-#define NR_ICMPMSG_COUNTERS	SNMP_PERLINE
+#define NR_ICMPMSG_COUNTERS     256     /* half of __ICMPMSG_MIB_MAX from kernel */
 
 enum {
     _PM_SNMP_IP_FORWARDING = 0,

commit 86590fd0132a6a0103f0de58c9fb8e47b3532f49
Author: Nathan Scott <nathans@redhat.com>
Date:   Wed Jan 22 15:08:41 2014 +1100

    Add test 844 exercising the unexpected-ICMP-packet-type pmdalinux fix

diff --git a/qa/844 b/qa/844
new file mode 100755
index 0000000..d033913
--- /dev/null
+++ b/qa/844
@@ -0,0 +1,41 @@
+#!/bin/sh
+# PCP QA Test No. 844
+# Exercise fix for Fedora bugzilla #1055818 -
+# pmdalinux segv on unexpected ICMP type field values
+#
+# Copyright (c) 2014 Red Hat.
+#
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+# get standard environment, filters and checks
+. ./common.product
+. ./common.filter
+. ./common.check
+
+which nmap >/dev/null 2>&1 || _notrun "nmap package not installed"
+which nping >/dev/null 2>&1 || _notrun "nping binary not installed"
+
+status=1	# failure is the default!
+$sudo rm -rf $tmp.* $seq.full
+trap "cd $here; rm -rf $tmp.*; exit \$status" 0 1 2 3 15
+
+_filter_icmp_metrics()
+{
+    sed \
+	-e "/network\..*\.incsumerrors: $unavailable/d" \
+    # end filter
+}
+
+# real QA test starts here
+$sudo nping --icmp --icmp-type 142 --quiet --count 1 localhost >$tmp.out 2>$tmp.err
+status=$?
+echo "nping status=$status"
+cat $tmp.out $tmp.err
+
+# verify we get good data (2x fetch for segv)
+pminfo -v network.icmp 2>&1 | _filter_icmp_metrics
+pminfo -v network.icmp 2>&1 | _filter_icmp_metrics
+
+exit
diff --git a/qa/844.out b/qa/844.out
new file mode 100755
index 0000000..a3f741c
--- /dev/null
+++ b/qa/844.out
@@ -0,0 +1,3 @@
+QA output created by 844
+nping status=0
+Warning: Specified ICMP type (142) is not RFC compliant.
diff --git a/qa/group b/qa/group
index a5fd816..45390c1 100644
--- a/qa/group
+++ b/qa/group
@@ -894,6 +894,7 @@ avahi
 831 pmda.sample pmstore secure local oss
 832 pmda.sample pmstore secure local oss
 840 avahi local oss
+844 pmda.linux local oss
 861 pmcd pmda.pmcd local oss
 875 libpcp local oss
 876 pmda.xfs local oss