Blame SOURCES/redhat-bugzilla-1981886-pmdasockets-backporting.patch

419cc7
diff --git a/qa/1927 b/qa/1927
419cc7
new file mode 100755
419cc7
index 000000000..46afa9509
419cc7
--- /dev/null
419cc7
+++ b/qa/1927
419cc7
@@ -0,0 +1,88 @@
419cc7
+#!/bin/sh
419cc7
+# PCP QA Test No. 1927
419cc7
+# Exercise the sockets PMDA Install/Remove and string metric bug.
419cc7
+#
419cc7
+# Copyright (c) 2022 Red Hat.  All Rights Reserved.
419cc7
+#
419cc7
+
419cc7
+seq=`basename $0`
419cc7
+echo "QA output created by $seq"
419cc7
+
419cc7
+# get standard environment, filters and checks
419cc7
+. ./common.product
419cc7
+. ./common.filter
419cc7
+. ./common.check
419cc7
+
419cc7
+[ -f $PCP_PMDAS_DIR/sockets/pmdasockets ] || _notrun "sockets pmda not installed"
419cc7
+
419cc7
+_cleanup()
419cc7
+{
419cc7
+    cd $here
419cc7
+    $sudo rm -rf $tmp $tmp.*
419cc7
+}
419cc7
+
419cc7
+status=0	# success is the default!
419cc7
+$sudo rm -rf $tmp $tmp.* $seq.full
419cc7
+
419cc7
+_filter_sockets()
419cc7
+{
419cc7
+    grep -v 'No value(s) available'
419cc7
+}
419cc7
+
419cc7
+pmdasockets_remove()
419cc7
+{
419cc7
+    echo
419cc7
+    echo "=== remove sockets agent ==="
419cc7
+    $sudo ./Remove >$tmp.out 2>&1
419cc7
+    _filter_pmda_remove <$tmp.out
419cc7
+}
419cc7
+
419cc7
+pmdasockets_install()
419cc7
+{
419cc7
+    # start from known starting points
419cc7
+    cd $PCP_PMDAS_DIR/sockets
419cc7
+    $sudo ./Remove >/dev/null 2>&1
419cc7
+
419cc7
+    echo
419cc7
+    echo "=== sockets agent installation ==="
419cc7
+    $sudo ./Install </dev/null >$tmp.out 2>&1
419cc7
+    cat $tmp.out >>$here/$seq.full
419cc7
+    # Check sockets metrics have appeared ... X metrics and Y values
419cc7
+    _filter_pmda_install <$tmp.out \
419cc7
+    | sed \
419cc7
+        -e 's/[0-9][0-9]* warnings, //' \
419cc7
+    | $PCP_AWK_PROG '
419cc7
+/Check network.persocket metrics have appeared/ {
419cc7
+                                          if ($7 >= 50 && $7 <= 99) $7 = "X"
419cc7
+                                          if ($10 >= 0) $10 = "Y"
419cc7
+                                        }
419cc7
+                                        { print }'
419cc7
+}
419cc7
+
419cc7
+_prepare_pmda sockets
419cc7
+# note: _restore_auto_restart pmcd done in _cleanup_pmda()
419cc7
+trap "_cleanup_pmda sockets; exit \$status" 0 1 2 3 15
419cc7
+
419cc7
+_stop_auto_restart pmcd
419cc7
+
419cc7
+# real QA test starts here
419cc7
+pmdasockets_install
419cc7
+
419cc7
+# pmcd should have been started by the Install process - check
419cc7
+if pminfo -v network.persocket > $tmp.info 2> $tmp.err
419cc7
+then
419cc7
+    :
419cc7
+else
419cc7
+    echo "... failed! ... here is the Install log ..."
419cc7
+    cat $tmp.out
419cc7
+fi
419cc7
+cat $tmp.info $tmp.err | _filter_sockets
419cc7
+
419cc7
+echo "Check the values for v6only metric are 0 or 1 ..."
419cc7
+pminfo -f network.persocket.v6only | egrep -v 'value [01]$' | sed -e '/^$/d'
419cc7
+
419cc7
+pmdasockets_remove
419cc7
+status=0
419cc7
+
419cc7
+# success, all done
419cc7
+exit
419cc7
diff --git a/qa/1927.out b/qa/1927.out
419cc7
new file mode 100644
419cc7
index 000000000..2ae4385fd
419cc7
--- /dev/null
419cc7
+++ b/qa/1927.out
419cc7
@@ -0,0 +1,17 @@
419cc7
+QA output created by 1927
419cc7
+
419cc7
+=== sockets agent installation ===
419cc7
+Updating the Performance Metrics Name Space (PMNS) ...
419cc7
+Terminate PMDA if already installed ...
419cc7
+[...install files, make output...]
419cc7
+Updating the PMCD control file, and notifying PMCD ...
419cc7
+Check network.persocket metrics have appeared ... X metrics and Y values
419cc7
+Check the values for v6only metric are 0 or 1 ...
419cc7
+network.persocket.v6only
419cc7
+
419cc7
+=== remove sockets agent ===
419cc7
+Culling the Performance Metrics Name Space ...
419cc7
+network.persocket ... done
419cc7
+Updating the PMCD control file, and notifying PMCD ...
419cc7
+[...removing files...]
419cc7
+Check network.persocket metrics have gone away ... OK
419cc7
diff --git a/qa/group b/qa/group
419cc7
index acfc5d208..846c0c4bd 100644
419cc7
--- a/qa/group
419cc7
+++ b/qa/group
419cc7
@@ -1967,6 +1967,7 @@ x11
419cc7
 1901 pmlogger local
419cc7
 1902 help local
419cc7
 1914 atop local
419cc7
+1927 pmda.sockets local
419cc7
 1937 pmlogrewrite pmda.xfs local
419cc7
 1955 libpcp pmda pmda.pmcd local
419cc7
 1956 pmda.linux pmcd local
419cc7
diff --git a/src/pmdas/linux_sockets/pmda.c b/src/pmdas/linux_sockets/pmda.c
419cc7
index d10eacf29..5a3018d8a 100644
419cc7
--- a/src/pmdas/linux_sockets/pmda.c
419cc7
+++ b/src/pmdas/linux_sockets/pmda.c
419cc7
@@ -1,7 +1,7 @@
419cc7
 /*
419cc7
  * Sockets PMDA
419cc7
  *
419cc7
- * Copyright (c) 2021 Red Hat.
419cc7
+ * Copyright (c) 2021-2022 Red Hat.
419cc7
  *
419cc7
  * This program is free software; you can redistribute it and/or modify it
419cc7
  * under the terms of the GNU General Public License as published by the
419cc7
@@ -14,6 +14,7 @@
419cc7
  * for more details.
419cc7
  */
419cc7
 
419cc7
+#include <ctype.h>
419cc7
 #include "pmapi.h"
419cc7
 #include "pmda.h"
419cc7
 
419cc7
@@ -147,6 +148,31 @@ sockets_fetchCallBack(pmdaMetric *metric, unsigned int inst, pmAtomValue *atom)
419cc7
     return PMDA_FETCH_STATIC;
419cc7
 }
419cc7
 
419cc7
+/*
419cc7
+ * Restrict the allowed filter strings to only limited special
419cc7
+ * characters (open and close brackets - everthing else can be
419cc7
+ * done with alphanumerics) to limit any attack surface here.
419cc7
+ * The ss filtering language is more complex than we ever want
419cc7
+ * to be attempting to parse ourself, so we leave that side of
419cc7
+ * things to the ss command itself.
419cc7
+ */
419cc7
+int
419cc7
+sockets_check_filter(const char *string)
419cc7
+{
419cc7
+    const char *p;
419cc7
+
419cc7
+    for (p = string; *p; p++) {
419cc7
+	if (isspace(*p))
419cc7
+	    continue;
419cc7
+	if (isalnum(*p))
419cc7
+	    continue;
419cc7
+	if (*p == '(' || *p == ')')
419cc7
+	    continue;
419cc7
+	return 0; /* disallow */
419cc7
+    }
419cc7
+    return 1;
419cc7
+}
419cc7
+
419cc7
 static int
419cc7
 sockets_store(pmResult *result, pmdaExt *pmda)
419cc7
 {
419cc7
@@ -165,9 +191,14 @@ sockets_store(pmResult *result, pmdaExt *pmda)
419cc7
 	    	case 0: /* network.persocket.filter */
419cc7
 		    if ((sts = pmExtractValue(vsp->valfmt, &vsp->vlist[0],
419cc7
 			PM_TYPE_STRING, &av, PM_TYPE_STRING)) >= 0) {
419cc7
+			if (sockets_check_filter(av.cp)) {
419cc7
+			    sts = PM_ERR_BADSTORE;
419cc7
+			    free(av.cp);
419cc7
+			    break;
419cc7
+			}
419cc7
 			if (ss_filter)
419cc7
 			    free(ss_filter);
419cc7
-			ss_filter = av.cp; /* TODO filter syntax check */
419cc7
+			ss_filter = av.cp;
419cc7
 		    }
419cc7
 		    break;
419cc7
 		default:
419cc7
diff --git a/src/pmdas/linux_sockets/ss_parse.c b/src/pmdas/linux_sockets/ss_parse.c
419cc7
index 94c5e16e9..9f3afc691 100644
419cc7
--- a/src/pmdas/linux_sockets/ss_parse.c
419cc7
+++ b/src/pmdas/linux_sockets/ss_parse.c
419cc7
@@ -1,5 +1,5 @@
419cc7
 /*
419cc7
- * Copyright (c) 2021 Red Hat.
419cc7
+ * Copyright (c) 2021-2022 Red Hat.
419cc7
  *
419cc7
  * This program is free software; you can redistribute it and/or modify it
419cc7
  * under the terms of the GNU General Public License as published by the
419cc7
@@ -21,65 +21,70 @@ static ss_stats_t ss_p;
419cc7
 /* boolean value with no separate value, default 0 */
419cc7
 #define PM_TYPE_BOOL (PM_TYPE_UNKNOWN-1)
419cc7
 
419cc7
+/* helper macros to extract field address and size */
419cc7
+#define SSFIELD(str,type,f) {(str), (sizeof(str)-1), type, (&(f)), (sizeof(f))}
419cc7
+#define SSNULLFIELD(str) {(str), (sizeof(str)-1), PM_TYPE_UNKNOWN, NULL}
419cc7
+
419cc7
 static struct {
419cc7
     char *field;
419cc7
     int len;
419cc7
     int type;
419cc7
     void *addr;
419cc7
+    int size;
419cc7
     int found;
419cc7
 } parse_table[] = {
419cc7
-    { "timer:", 6, PM_TYPE_STRING, &ss_p.timer_str },
419cc7
-    { "uid:", 4, PM_TYPE_U32, &ss_p.uid },
419cc7
-    { "ino:", 4, PM_TYPE_64, &ss_p.inode },
419cc7
-    { "sk:", 3, PM_TYPE_U64, &ss_p.sk },
419cc7
-    { "cgroup:", 7, PM_TYPE_STRING, &ss_p.cgroup },
419cc7
-    { "v6only:", 7, PM_TYPE_32, &ss_p.v6only },
419cc7
-    { "--- ", 4, PM_TYPE_UNKNOWN, NULL  },
419cc7
-    { "<-> ", 4, PM_TYPE_UNKNOWN, NULL  },
419cc7
-    { "--> ", 4, PM_TYPE_UNKNOWN, NULL  },
419cc7
-    { "skmem:", 6, PM_TYPE_STRING, &ss_p.skmem_str,  },
419cc7
-    { "ts ", 3, PM_TYPE_BOOL, &ss_p.ts },
419cc7
-    { "sack ", 5, PM_TYPE_BOOL, &ss_p.sack },
419cc7
-    { "cubic ", 6, PM_TYPE_BOOL, &ss_p.cubic },
419cc7
-    { "wscale:", 7, PM_TYPE_STRING, &ss_p.wscale_str },
419cc7
-    { "rto:", 4, PM_TYPE_DOUBLE, &ss_p.rto },
419cc7
-    { "rtt:", 4, PM_TYPE_STRING, &ss_p.round_trip_str  },
419cc7
-    { "ato:", 4, PM_TYPE_DOUBLE, &ss_p.ato },
419cc7
-    { "backoff:", 8, PM_TYPE_32, &ss_p.backoff },
419cc7
-    { "mss:", 4, PM_TYPE_U32, &ss_p.mss },
419cc7
-    { "pmtu:", 5, PM_TYPE_U32, &ss_p.pmtu },
419cc7
-    { "rcvmss:", 7, PM_TYPE_U32, &ss_p.rcvmss },
419cc7
-    { "advmss:", 7, PM_TYPE_U32, &ss_p.advmss },
419cc7
-    { "cwnd:", 5, PM_TYPE_U32, &ss_p.cwnd },
419cc7
-    { "lost:", 5, PM_TYPE_32, &ss_p.lost },
419cc7
-    { "ssthresh:", 9, PM_TYPE_U32, &ss_p.ssthresh },
419cc7
-    { "bytes_sent:", 11, PM_TYPE_U64, &ss_p.bytes_sent },
419cc7
-    { "bytes_retrans:", 14, PM_TYPE_U64, &ss_p.bytes_retrans },
419cc7
-    { "bytes_acked:", 12, PM_TYPE_U64, &ss_p.bytes_acked },
419cc7
-    { "bytes_received:", 15, PM_TYPE_U64, &ss_p.bytes_received },
419cc7
-    { "segs_out:", 9, PM_TYPE_U32, &ss_p.segs_out },
419cc7
-    { "segs_in:", 8, PM_TYPE_U32, &ss_p.segs_in },
419cc7
-    { "data_segs_out:", 14, PM_TYPE_U32, &ss_p.data_segs_out },
419cc7
-    { "data_segs_in:", 13, PM_TYPE_U32, &ss_p.data_segs_in },
419cc7
-    { "send ", 5, PM_TYPE_DOUBLE, &ss_p.send }, /* no ':' */
419cc7
-    { "lastsnd:", 8, PM_TYPE_U32, &ss_p.lastsnd },
419cc7
-    { "lastrcv:", 8, PM_TYPE_U32, &ss_p.lastrcv },
419cc7
-    { "lastack:", 8, PM_TYPE_U32, &ss_p.lastack },
419cc7
-    { "pacing_rate ", 12, PM_TYPE_DOUBLE, &ss_p.pacing_rate }, /* no ':' */
419cc7
-    { "delivery_rate ", 14, PM_TYPE_DOUBLE, &ss_p.delivery_rate }, /* no ':' */
419cc7
-    { "delivered:", 10, PM_TYPE_U32, &ss_p.delivered },
419cc7
-    { "app_limited ", 12, PM_TYPE_BOOL, &ss_p.app_limited },
419cc7
-    { "reord_seen:", 11, PM_TYPE_32, &ss_p.reord_seen },
419cc7
-    { "busy:", 5, PM_TYPE_U64, &ss_p.busy },
419cc7
-    { "unacked:", 8, PM_TYPE_32, &ss_p.unacked },
419cc7
-    { "rwnd_limited:", 13, PM_TYPE_U64, &ss_p.rwnd_limited },
419cc7
-    { "retrans:", 8, PM_TYPE_STRING, &ss_p.retrans_str },
419cc7
-    { "dsack_dups:", 11, PM_TYPE_U32, &ss_p.dsack_dups },
419cc7
-    { "rcv_rtt:", 8, PM_TYPE_DOUBLE, &ss_p.rcv_rtt },
419cc7
-    { "rcv_space:", 10, PM_TYPE_32, &ss_p.rcv_space },
419cc7
-    { "rcv_ssthresh:", 13, PM_TYPE_32, &ss_p.rcv_ssthresh },
419cc7
-    { "minrtt:", 7, PM_TYPE_DOUBLE, &ss_p.minrtt },
419cc7
-    { "notsent:", 8, PM_TYPE_U32, &ss_p.notsent },
419cc7
+    SSFIELD("timer:", PM_TYPE_STRING, ss_p.timer_str),
419cc7
+    SSFIELD("uid:", PM_TYPE_U32, ss_p.uid),
419cc7
+    SSFIELD("ino:", PM_TYPE_64, ss_p.inode),
419cc7
+    SSFIELD("sk:", PM_TYPE_U64, ss_p.sk),
419cc7
+    SSFIELD("cgroup:", PM_TYPE_STRING, ss_p.cgroup),
419cc7
+    SSFIELD("v6only:", PM_TYPE_32, ss_p.v6only),
419cc7
+    SSNULLFIELD("--- "),
419cc7
+    SSNULLFIELD("<-> "),
419cc7
+    SSNULLFIELD("--> "),
419cc7
+    SSFIELD("skmem:", PM_TYPE_STRING, ss_p.skmem_str),
419cc7
+    SSFIELD("ts ", PM_TYPE_BOOL, ss_p.ts),
419cc7
+    SSFIELD("sack ", PM_TYPE_BOOL, ss_p.sack),
419cc7
+    SSFIELD("cubic ", PM_TYPE_BOOL, ss_p.cubic),
419cc7
+    SSFIELD("wscale:", PM_TYPE_STRING, ss_p.wscale_str),
419cc7
+    SSFIELD("rto:", PM_TYPE_DOUBLE, ss_p.rto),
419cc7
+    SSFIELD("rtt:", PM_TYPE_STRING, ss_p.round_trip_str),
419cc7
+    SSFIELD("ato:", PM_TYPE_DOUBLE, ss_p.ato),
419cc7
+    SSFIELD("backoff:", PM_TYPE_32, ss_p.backoff),
419cc7
+    SSFIELD("mss:", PM_TYPE_U32, ss_p.mss),
419cc7
+    SSFIELD("pmtu:", PM_TYPE_U32, ss_p.pmtu),
419cc7
+    SSFIELD("rcvmss:", PM_TYPE_U32, ss_p.rcvmss),
419cc7
+    SSFIELD("advmss:", PM_TYPE_U32, ss_p.advmss),
419cc7
+    SSFIELD("cwnd:", PM_TYPE_U32, ss_p.cwnd),
419cc7
+    SSFIELD("lost:", PM_TYPE_32, ss_p.lost),
419cc7
+    SSFIELD("ssthresh:", PM_TYPE_U32, ss_p.ssthresh),
419cc7
+    SSFIELD("bytes_sent:", PM_TYPE_U64, ss_p.bytes_sent),
419cc7
+    SSFIELD("bytes_retrans:", PM_TYPE_U64, ss_p.bytes_retrans),
419cc7
+    SSFIELD("bytes_acked:", PM_TYPE_U64, ss_p.bytes_acked),
419cc7
+    SSFIELD("bytes_received:", PM_TYPE_U64, ss_p.bytes_received),
419cc7
+    SSFIELD("segs_out:", PM_TYPE_U32, ss_p.segs_out),
419cc7
+    SSFIELD("segs_in:", PM_TYPE_U32, ss_p.segs_in),
419cc7
+    SSFIELD("data_segs_out:", PM_TYPE_U32, ss_p.data_segs_out),
419cc7
+    SSFIELD("data_segs_in:", PM_TYPE_U32, ss_p.data_segs_in),
419cc7
+    SSFIELD("send ", PM_TYPE_DOUBLE, ss_p.send), /* no ':' */
419cc7
+    SSFIELD("lastsnd:", PM_TYPE_U32, ss_p.lastsnd),
419cc7
+    SSFIELD("lastrcv:", PM_TYPE_U32, ss_p.lastrcv),
419cc7
+    SSFIELD("lastack:", PM_TYPE_U32, ss_p.lastack),
419cc7
+    SSFIELD("pacing_rate ", PM_TYPE_DOUBLE, ss_p.pacing_rate), /* no ':' */
419cc7
+    SSFIELD("delivery_rate ", PM_TYPE_DOUBLE, ss_p.delivery_rate), /* no ':' */
419cc7
+    SSFIELD("delivered:", PM_TYPE_U32, ss_p.delivered),
419cc7
+    SSFIELD("app_limited ", PM_TYPE_BOOL, ss_p.app_limited),
419cc7
+    SSFIELD("reord_seen:", PM_TYPE_32, ss_p.reord_seen),
419cc7
+    SSFIELD("busy:", PM_TYPE_U64, ss_p.busy),
419cc7
+    SSFIELD("unacked:", PM_TYPE_32, ss_p.unacked),
419cc7
+    SSFIELD("rwnd_limited:", PM_TYPE_U64, ss_p.rwnd_limited),
419cc7
+    SSFIELD("retrans:", PM_TYPE_STRING, ss_p.retrans_str),
419cc7
+    SSFIELD("dsack_dups:", PM_TYPE_U32, ss_p.dsack_dups),
419cc7
+    SSFIELD("rcv_rtt:", PM_TYPE_DOUBLE, ss_p.rcv_rtt),
419cc7
+    SSFIELD("rcv_space:", PM_TYPE_32, ss_p.rcv_space),
419cc7
+    SSFIELD("rcv_ssthresh:", PM_TYPE_32, ss_p.rcv_ssthresh),
419cc7
+    SSFIELD("minrtt:", PM_TYPE_DOUBLE, ss_p.minrtt),
419cc7
+    SSFIELD("notsent:", PM_TYPE_U32, ss_p.notsent),
419cc7
 
419cc7
     { NULL }
419cc7
 };
419cc7
@@ -225,8 +230,11 @@ ss_parse(char *line, int has_state_field, ss_stats_t *ss)
419cc7
 		    if (*p == '(')
419cc7
 		    	p++;
419cc7
 		    r = (char *)parse_table[i].addr;
419cc7
-		    for (s=p; *s && *s != ' ' && *s != '\n' && *s != ')'; s++)
419cc7
-			*r++ = *s; /* TODO check r len */
419cc7
+		    for (s=p; *s && *s != ' ' && *s != '\n' && *s != ')'; s++) {
419cc7
+			*r++ = *s;
419cc7
+			if (r - (char *)parse_table[i].addr >= parse_table[i].size - 1)
419cc7
+			    break;
419cc7
+		    }
419cc7
 		    *r = '\0';
419cc7
 		    break;
419cc7
 		case PM_TYPE_32:
419cc7
diff --git a/src/pmdas/linux_sockets/ss_stats.h b/src/pmdas/linux_sockets/ss_stats.h
419cc7
index 183db5afa..009a00cd9 100644
419cc7
--- a/src/pmdas/linux_sockets/ss_stats.h
419cc7
+++ b/src/pmdas/linux_sockets/ss_stats.h
419cc7
@@ -1,11 +1,11 @@
419cc7
 /*
419cc7
- * Copyright (c) 2021 Red Hat.
419cc7
- * 
419cc7
+ * Copyright (c) 2021-2022 Red Hat.
419cc7
+ *
419cc7
  * This program is free software; you can redistribute it and/or modify it
419cc7
  * under the terms of the GNU General Public License as published by the
419cc7
  * Free Software Foundation; either version 2 of the License, or (at your
419cc7
  * option) any later version.
419cc7
- * 
419cc7
+ *
419cc7
  * This program is distributed in the hope that it will be useful, but
419cc7
  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
419cc7
  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
419cc7
@@ -26,7 +26,7 @@ typedef struct ss_stats {
419cc7
     __int32_t		timer_retrans;
419cc7
     __uint32_t		uid;
419cc7
     __uint64_t		sk;
419cc7
-    char		cgroup[64];
419cc7
+    char		cgroup[128];
419cc7
     __int32_t		v6only;
419cc7
     char		skmem_str[64];
419cc7
     __int32_t		skmem_rmem_alloc;