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