From 54531fc4036b82e364da014d43ed74613dfebac1 Mon Sep 17 00:00:00 2001 From: Jan Kurik Date: Wed, 12 Aug 2026 11:57:52 +0200 Subject: [PATCH] Backport remaining PCP security CVE fixes for 7.1.5-5 Add patches for CVE-2026-16524, CVE-2026-16526, CVE-2026-16527, and CVE-2026-16529 so all TIM security fixes tracked for RHEL 10.3 are present alongside the previously shipped CVE-2026-16530/16531 fixes. Co-authored-by: Cursor --- pcp-7.1.5-CVE-2026-16524.patch | 257 +++++ pcp-7.1.5-CVE-2026-16526.patch | 1717 ++++++++++++++++++++++++++++++++ pcp-7.1.5-CVE-2026-16527.patch | 197 ++++ pcp-7.1.5-CVE-2026-16529.patch | 149 +++ pcp.spec | 24 +- 5 files changed, 2343 insertions(+), 1 deletion(-) create mode 100644 pcp-7.1.5-CVE-2026-16524.patch create mode 100644 pcp-7.1.5-CVE-2026-16526.patch create mode 100644 pcp-7.1.5-CVE-2026-16527.patch create mode 100644 pcp-7.1.5-CVE-2026-16529.patch diff --git a/pcp-7.1.5-CVE-2026-16524.patch b/pcp-7.1.5-CVE-2026-16524.patch new file mode 100644 index 0000000..477f0eb --- /dev/null +++ b/pcp-7.1.5-CVE-2026-16524.patch @@ -0,0 +1,257 @@ +From c5cbeceb7d Mon Sep 17 00:00:00 2001 +From: Nathan Scott +Subject: [PATCH] linux_sockets pmda: fix command injection via network.persocket.filter (CWE-78) + +The sockets_check_filter() validation helper returns 1 for safe input +and 0 for unsafe input. The guard in sockets_store() tested +if (sockets_check_filter(av.cp)) — rejecting safe input and accepting +malicious input containing shell metacharacters. The accepted filter +was later passed to popen() via shell interpretation, enabling arbitrary +command execution as the PMDA process user. + +Fix: +- Invert the guard: if (!sockets_check_filter(av.cp)) +- Replace popen()/pclose() in ss_open_stream() with the libpcp + __pmProcessAddArg()/__pmProcessPipe()/__pmProcessPipeClose() API + which uses execvp() internally, eliminating shell interpretation + of the filter string entirely +- Add qa/2101 verifying that valid filters are accepted and shell + metacharacters (semicolons, backticks, pipes) are rejected + +Reported-by: Francisco Alisson Bezerra, TIM Security Red Team +Reported-by: Lucas Gabriel Alves, TIM Security Red Team +Reported-by: Massimiliano Brolli, TIM Security Red Team + +Co-Authored-By: Claude Opus 4.6 (1M context) + +Resolves: RHEL-213661 +--- +diff --git a/qa/2101 b/qa/2101 +new file mode 100755 +index 0000000000..733b7f70c9 +--- /dev/null ++++ b/qa/2101 +@@ -0,0 +1,70 @@ ++#!/bin/sh ++# PCP QA Test No. 2101 ++# Verify linux_sockets PMDA filter validation rejects shell metacharacters ++# and accepts valid filter expressions (CWE-78 fix verification) ++# ++# Copyright (c) 2026 Red Hat. All Rights Reserved. ++# ++ ++seq=`basename $0` ++echo "QA output created by $seq" ++ ++# get standard environment, filters and checks ++. ./common.product ++. ./common.filter ++. ./common.check ++ ++[ $PCP_PLATFORM = linux ] || _notrun "Linux-specific sockets testing" ++[ -f $PCP_PMDAS_DIR/sockets/pmdasockets ] || _notrun "sockets PMDA not installed" ++ ++_cleanup() ++{ ++ _cleanup_pmda sockets ++ cd $here ++ $sudo rm -rf $tmp $tmp.* ++} ++ ++status=0 # success is the default! ++trap "_cleanup; exit \$status" 0 1 2 3 15 ++ ++_prepare_pmda sockets ++_stop_auto_restart pmcd ++ ++# install the sockets PMDA ++cd $PCP_PMDAS_DIR/sockets ++$sudo ./Remove >/dev/null 2>&1 ++$sudo ./Install $tmp.out 2>&1 ++cat $tmp.out >>$seq_full ++ ++# check the PMDA is alive ++pmprobe -v network.persocket.filter >$tmp.probe 2>&1 ++grep -q 'No PMCD agent' $tmp.probe && _notrun "sockets PMDA failed to install" ++ ++# real QA test starts here ++ ++echo "=== valid filter should be accepted ===" ++pmstore network.persocket.filter "sport == 22" 2>&1 \ ++| grep -q 'Bad input' && echo "FAIL: valid filter rejected" || echo "valid filter accepted" ++ ++echo ++echo "=== shell metacharacter semicolon should be rejected ===" ++pmstore network.persocket.filter ';id' 2>&1 \ ++| grep -q 'Bad input' && echo "metacharacter rejected" || echo "FAIL: metacharacter not rejected" ++ ++echo ++echo "=== shell metacharacter backtick should be rejected ===" ++pmstore network.persocket.filter '`id`' 2>&1 \ ++| grep -q 'Bad input' && echo "metacharacter rejected" || echo "FAIL: metacharacter not rejected" ++ ++echo ++echo "=== shell metacharacter pipe should be rejected ===" ++pmstore network.persocket.filter '|cat /etc/passwd' 2>&1 \ ++| grep -q 'Bad input' && echo "metacharacter rejected" || echo "FAIL: metacharacter not rejected" ++ ++echo ++echo "=== shell metacharacter dollar should be rejected ===" ++pmstore network.persocket.filter '${IFS}id' 2>&1 \ ++| grep -q 'Bad input' && echo "metacharacter rejected" || echo "FAIL: metacharacter not rejected" ++ ++# success, all done ++exit +diff --git a/qa/2101.out b/qa/2101.out +new file mode 100644 +index 0000000000..02f9ac5655 +--- /dev/null ++++ b/qa/2101.out +@@ -0,0 +1,15 @@ ++QA output created by 2101 ++=== valid filter should be accepted === ++valid filter accepted ++ ++=== shell metacharacter semicolon should be rejected === ++metacharacter rejected ++ ++=== shell metacharacter backtick should be rejected === ++metacharacter rejected ++ ++=== shell metacharacter pipe should be rejected === ++metacharacter rejected ++ ++=== shell metacharacter dollar should be rejected === ++metacharacter rejected +diff --git a/qa/group b/qa/group +index 1533ad5720..2c6529b718 100644 +--- a/qa/group ++++ b/qa/group +@@ -2375,5 +2375,6 @@ suse + 2105 libpcp pmcd local security pmcd.pdu + 2100 pmproxy local security + 2104 libpcp local security ++2101 pmda.sockets local security + 4751 libpcp threads valgrind local pcp helgrind + 9000 other local +diff --git a/src/pmdas/linux_sockets/pmda.c b/src/pmdas/linux_sockets/pmda.c +index 4d51207275..2cb46d8e89 100644 +--- a/src/pmdas/linux_sockets/pmda.c ++++ b/src/pmdas/linux_sockets/pmda.c +@@ -162,11 +162,9 @@ sockets_check_filter(const char *string) + const char *p; + + for (p = string; *p; p++) { +- if (isspace(*p)) ++ if (isspace(*p) || isalnum(*p)) + continue; +- if (isalnum(*p)) +- continue; +- if (*p == '(' || *p == ')') ++ if (strchr("()=!<>:.*/-,", *p) != NULL) + continue; + return 0; /* disallow */ + } +@@ -191,7 +189,7 @@ sockets_store(pmdaResult *result, pmdaExt *pmda) + case 0: /* network.persocket.filter */ + if ((sts = pmExtractValue(vsp->valfmt, &vsp->vlist[0], + PM_TYPE_STRING, &av, PM_TYPE_STRING)) >= 0) { +- if (sockets_check_filter(av.cp)) { ++ if (!sockets_check_filter(av.cp)) { + sts = PM_ERR_BADSTORE; + free(av.cp); + break; +diff --git a/src/pmdas/linux_sockets/ss_stream.c b/src/pmdas/linux_sockets/ss_stream.c +index 421c65fd16..833fc275a0 100644 +--- a/src/pmdas/linux_sockets/ss_stream.c ++++ b/src/pmdas/linux_sockets/ss_stream.c +@@ -14,18 +14,19 @@ + + #include + #include ++#include + #include "ss_stats.h" + + #define SS_OPTIONS "-noemitauO" + +-char *ss_filter = NULL; /* storable: network.persocket.filter */ ++char *ss_filter; /* storable: network.persocket.filter */ ++static int using_pipe; /* pipe is normal operation, QA uses files */ + + FILE * + ss_open_stream() + { +- FILE *fp; ++ FILE *fp = NULL; + char *path; +- char cmd[MAXPATHLEN]; + + if (ss_filter == NULL) { + /* pmstore to network.persocket.filter frees this if changing */ +@@ -38,17 +39,51 @@ ss_open_stream() + fp = fopen(path, "r"); + if (pmDebugOptions.appl0) + fprintf(stderr, "ss_open_stream: open PCPQA_PMDA_SOCKETS=%s\n", path); ++ using_pipe = 0; + } else { ++ __pmExecCtl_t *argp = NULL; ++ int sts; ++ + if (access((path = "/usr/sbin/ss"), X_OK) != 0) { + if (access((path = "/usr/bin/ss"), X_OK) != 0) { + fprintf(stderr, "Error: no \"ss\" binary found\n"); + return NULL; + } + } +- pmsprintf(cmd, sizeof(cmd), "%s %s %s", path, SS_OPTIONS, ss_filter); +- fp = popen(cmd, "r"); ++ if ((sts = __pmProcessAddArg(&argp, path)) < 0 || ++ (sts = __pmProcessAddArg(&argp, SS_OPTIONS)) < 0) { ++ if (pmDebugOptions.appl0) ++ fprintf(stderr, "ss_open_stream: __pmProcessAddArg failed: %s\n", ++ pmErrStr(sts)); ++ return NULL; ++ } ++ if (ss_filter[0] != '\0') { ++ char *s, *tok, *saveptr; ++ ++ if ((s = strdup(ss_filter)) == NULL) ++ return NULL; ++ for (tok = strtok_r(s, " \t", &saveptr); tok != NULL; ++ tok = strtok_r(NULL, " \t", &saveptr)) { ++ if ((sts = __pmProcessAddArg(&argp, tok)) < 0) { ++ free(s); ++ if (pmDebugOptions.appl0) ++ fprintf(stderr, "ss_open_stream: __pmProcessAddArg failed: %s\n", ++ pmErrStr(sts)); ++ return NULL; ++ } ++ } ++ free(s); ++ } ++ if ((sts = __pmProcessPipe(&argp, "r", PM_EXEC_TOSS_NONE, &fp)) < 0) { ++ if (pmDebugOptions.appl0) ++ fprintf(stderr, "ss_open_stream: __pmProcessPipe failed: %s\n", ++ pmErrStr(sts)); ++ return NULL; ++ } + if (pmDebugOptions.appl0) +- fprintf(stderr, "ss_open_stream: popen %s\n", cmd); ++ fprintf(stderr, "ss_open_stream: exec %s %s %s\n", ++ path, SS_OPTIONS, ss_filter); ++ using_pipe = 1; + } + + return fp; +@@ -57,8 +92,8 @@ ss_open_stream() + void + ss_close_stream(FILE *fp) + { +- if (getenv("PCPQA_PMDA_SOCKETS") != NULL) +- fclose(fp); ++ if (using_pipe) ++ __pmProcessPipeClose(fp); + else +- pclose(fp); ++ fclose(fp); + } diff --git a/pcp-7.1.5-CVE-2026-16526.patch b/pcp-7.1.5-CVE-2026-16526.patch new file mode 100644 index 0000000..3606d5d --- /dev/null +++ b/pcp-7.1.5-CVE-2026-16526.patch @@ -0,0 +1,1717 @@ +From 7e27614006 Mon Sep 17 00:00:00 2001 +From: Nathan Scott +Subject: [PATCH] libpcp, libpcp_pmda: set FD_CLOEXEC on AF_UNIX sockets (CWE-403) + +The __pmInitSocket() function returns early for AF_UNIX sockets, +skipping all subsequent socket hardening including FD_CLOEXEC. +This causes the pmdaroot Unix socket fd to be inherited by child +processes spawned via popen()/fork(), enabling privilege escalation +when combined with the linux_sockets command injection (vuln 3): +an attacker's popen() child inherits the pmdaroot fd and can send +a PDUROOT_STARTPMDA_REQ to execute commands as root. + +Fix: +- Set FD_CLOEXEC on AF_UNIX sockets in __pmInitSocket() before the + early return, matching the behavior TCP sockets get via + __pmConnectRestoreFlags() +- Set FD_CLOEXEC on pmdarootfd in pmdaRootConnect() after connect() + succeeds, as belt-and-suspenders for this critical fd +- Add qa/src/check_cloexec.c and qa/2104 verifying FD_CLOEXEC is set + on sockets created by __pmCreateUnixSocket() + +Note: SO_PEERCRED peer credential verification on the pmdaroot server +side is a separate hardening measure to be addressed as a follow-up. + +Reported-by: Francisco Alisson Bezerra, TIM Security Red Team +Reported-by: Lucas Gabriel Alves, TIM Security Red Team +Reported-by: Massimiliano Brolli, TIM Security Red Team + +Co-Authored-By: Claude Opus 4.6 (1M context) + +Resolves: RHEL-213692 +--- +diff --git a/qa/2104 b/qa/2104 +new file mode 100755 +index 0000000000..0b2b0b602e +--- /dev/null ++++ b/qa/2104 +@@ -0,0 +1,31 @@ ++#!/bin/sh ++# PCP QA Test No. 2104 ++# Verify AF_UNIX sockets have FD_CLOEXEC set (CWE-403 fix) ++# ++# Copyright (c) 2026 Red Hat. All Rights Reserved. ++# ++ ++seq=`basename $0` ++echo "QA output created by $seq" ++ ++# get standard environment, filters and checks ++. ./common.product ++. ./common.filter ++. ./common.check ++ ++[ -f src/check_cloexec ] || _notrun "check_cloexec not built" ++ ++_cleanup() ++{ ++ cd $here ++ $sudo rm -rf $tmp $tmp.* ++} ++ ++status=0 # success is the default! ++trap "_cleanup; exit \$status" 0 1 2 3 15 ++ ++# real QA test starts here ++src/check_cloexec ++ ++# success, all done ++exit +diff --git a/qa/2104.out b/qa/2104.out +new file mode 100644 +index 0000000000..900a95ec75 +--- /dev/null ++++ b/qa/2104.out +@@ -0,0 +1,2 @@ ++QA output created by 2104 ++FD_CLOEXEC is set +diff --git a/qa/group b/qa/group +index 92c27dc49f..1533ad5720 100644 +--- a/qa/group ++++ b/qa/group +@@ -2374,5 +2374,6 @@ suse + 2106 pmproxy local security + 2105 libpcp pmcd local security pmcd.pdu + 2100 pmproxy local security ++2104 libpcp local security + 4751 libpcp threads valgrind local pcp helgrind + 9000 other local +diff --git a/qa/src/GNUlocaldefs b/qa/src/GNUlocaldefs +index dd152a6412..2009bd65b0 100644 +--- a/qa/src/GNUlocaldefs ++++ b/qa/src/GNUlocaldefs +@@ -1,5 +1,5 @@ + # +-# Copyright (c) 2012-2021 Red Hat. ++# Copyright (c) 2012-2026 Red Hat. + # Copyright (c) 2009 Aconex. All Rights Reserved. + # Copyright (c) 1997-2002 Silicon Graphics, Inc. All Rights Reserved. + # +@@ -36,7 +36,8 @@ CFILES = disk_test.c exercise.c context_test.c chkoptfetch.c \ + mmv2_genstats.c mmv2_instances.c mmv2_nostats.c mmv2_simple.c \ + mmv3_simple.c mmv3_labels.c mmv3_bad_labels.c mmv3_nostats.c mmv3_genstats.c \ + record.c record-setarg.c clientid.c grind_ctx.c \ +- pmdacache.c check_import.c unpack.c hrunpack.c aggrstore.c atomstr.c \ ++ check_import_append.c check_import_name.c check_import.c check_volsize.c \ ++ pmdacache.c unpack.c hrunpack.c aggrstore.c atomstr.c \ + semstr.c grind_conv.c getconfig.c err.c torture_logmeta.c keycache.c \ + keycache2.c pmdaqueue.c drain-server.c template.c anon-sa.c \ + username.c rtimetest.c getcontexthost.c badpmda.c chklogputresult.c \ +@@ -56,7 +57,14 @@ CFILES = disk_test.c exercise.c context_test.c chkoptfetch.c \ + throttle.c throttle_timeout.c y2038.c bigpmcdpmids.c pdu-gadget.c \ + strnfoo.c mmv_ondisk.c newcontext.c api_abi.c interp_bug3.c \ + pmsetmode.c scanindex.c localtime.c httpcache.c unregister.c \ +- genpmns.c undelta.c series_time_parse_test.c derived_control.c ++ genpmns.c undelta.c series_time_parse_test.c derived_control.c \ ++ multithread0.c multithread1.c multithread2.c multithread3.c \ ++ multithread4.c multithread5.c multithread6.c multithread7.c \ ++ multithread8.c multithread9.c multithread10.c multithread11.c \ ++ multithread12.c multithread13.c multithread14.c \ ++ exerlock.c hashwalk.c parsehostattrs.c parsehostspec.c getoptions.c \ ++ check_cloexec.c ++ + + ifeq ($(shell test -f ../localconfig && echo 1), 1) + include ../localconfig +@@ -68,53 +76,7 @@ $(error Cannot make qa/localconfig) + endif + endif + +-ifeq ($(shell test $(PCP_VER) -ge 3600 && echo 1), 1) +-CFILES += multithread0.c multithread1.c multithread2.c multithread3.c \ +- multithread4.c multithread5.c multithread6.c multithread7.c \ +- multithread8.c multithread9.c multithread10.c multithread11.c \ +- multithread12.c multithread13.c multithread14.c \ +- exerlock.c +-else +-MYFILES += multithread0.c multithread1.c multithread2.c multithread3.c \ +- multithread4.c multithread5.c multithread6.c multithread7.c \ +- multithread8.c multithread9.c multithread10.c multithread11.c \ +- multithread12.c multithread13.c multithread14.c \ +- exerlock.c +-LDIRT += multithread0 multithread1 multithread2 multithread3 \ +- multithread4 multithread5 multithread6 multithread7 \ +- multithread8 multithread9 multithread10 multithread11 \ +- multithread12 multithread13 multithread14 \ +- exerlock +-endif +- +-ifeq ($(shell test $(PCP_VER) -ge 3700 && echo 1), 1) +-CFILES += hashwalk.c +-else +-MYFILES += hashwalk.c +-LDIRT += hashwalk +-endif +- +-ifeq ($(shell test $(PCP_VER) -ge 3800 && echo 1), 1) +-CFILES += parsehostattrs.c parsehostspec.c check_import_name.c +-else +-MYFILES += parsehostattrs.c parsehostspec.c check_import_name.c +-LDIRT += parsehostattrs parsehostspec check_import_name +-endif +- +-ifeq ($(shell test $(PCP_VER) -ge 3802 && echo 1), 1) +-POSIXFILES += chkacc4.c +-else +-MYFILES += chkacc4.c +-LDIRT += chkacc4 +-endif +- +-ifeq ($(shell test $(PCP_VER) -ge 3901 && echo 1), 1) +-CFILES += getoptions.c + XTRATARGETS += getoptions_v2 +-else +-MYFILES += getoptions.c +-LDIRT += getoptions getoptions_v2 +-endif + + ifeq ($(shell test -f /usr/include/pcp/fault.h && echo 1), 1) + # only make these ones if the fault injection version of libpcp +@@ -142,7 +104,7 @@ endif + # + POSIXFILES = \ + ipc.c proc_test.c context_fd_leak.c arch_maxfd.c torture_trace.c \ +- 779246.c killparent.c fetchloop.c chain.c spawn.c ++ 779246.c killparent.c fetchloop.c chain.c spawn.c chkacc4.c + + TRACEFILES = \ + obs.c tstate.c tabort.c +@@ -284,63 +246,88 @@ statvfs: statvfs.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ statvfs.c + +-pause: pause.c +- $(CCF) $(CDEFS) -o pause pause.c ++chain: chain.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ chain.c + +-errmap: errmap.c +- $(CCF) $(CDEFS) -o errmap errmap.c ++spawn: spawn.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ spawn.c + +-cpuload: cpuload.c ++endian: endian.c localconfig.h + rm -f $@ +- $(CCF) $(CDEFS) -o $@ cpuload.c ++ $(CCF) $(CDEFS) -o $@ endian.c + +-load_o2000: load_o2000.c ++pmlcmacro: pmlcmacro.c + rm -f $@ +- $(CCF) $(CDEFS) -o $@ load_o2000.c ++ $(CCF) $(CDEFS) -o $@ pmlcmacro.c + +-chain: chain.c ++anon-sa: anon-sa.c + rm -f $@ +- $(CCF) $(CDEFS) -o $@ chain.c ++ $(CCF) $(CDEFS) -o $@ anon-sa.c + +-syscall: syscall.c ++bcc_profile: bcc_profile.c + rm -f $@ +- $(CCF) $(CDEFS) -o $@ syscall.c ++ $(CCF) $(CDEFS) -g -fno-omit-frame-pointer -o $@ bcc_profile.c + +-getpagesize: getpagesize.c ++sizeof: sizeof.c + rm -f $@ +- $(CCF) $(CDEFS) -o $@ getpagesize.c ++ $(CCF) $(CDEFS) -o $@ $< + +-rdwr: rdwr.c ++args: args.c + rm -f $@ +- $(CCF) $(CDEFS) -o $@ rdwr.c ++ $(CCF) $(CDEFS) -o $@ $< + +-spawn: spawn.c ++hanoi: hanoi.c + rm -f $@ +- $(CCF) $(CDEFS) -o $@ spawn.c ++ $(CCF) $(CDEFS) -o $@ $< + +-diowr: diowr.c ++infiniband-verbs: infiniband-verbs.c + rm -f $@ +- $(CCF) $(CDEFS) -o $@ diowr.c ++ $(CCF) $(CDEFS) -o $@ $< + +-endian: endian.c localconfig.h ++killparent: killparent.c + rm -f $@ +- $(CCF) $(CDEFS) -o $@ endian.c ++ $(CCF) $(CDEFS) -o $@ $< + +-pmlcmacro: pmlcmacro.c ++matchInstanceName: matchInstanceName.c + rm -f $@ +- $(CCF) $(CDEFS) -o $@ pmlcmacro.c ++ $(CCF) $(CDEFS) -o $@ $< + +-sys5_ipc: sys5_ipc.c ++qa_msgctl_stat: qa_msgctl_stat.c + rm -f $@ +- $(CCF) $(CDEFS) -o $@ sys5_ipc.c ++ $(CCF) $(CDEFS) -o $@ $< + +-anon-sa: anon-sa.c +- $(CCF) $(CDEFS) -o $@ anon-sa.c ++qa_sem_msg_ctl: qa_sem_msg_ctl.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< + +-bcc_profile: bcc_profile.c +- $(CCF) $(CDEFS) -g -fno-omit-frame-pointer -o $@ bcc_profile.c ++qa_semctl_stat: qa_semctl_stat.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< + +-sizeof: sizeof.c ++qa_shmctl_stat: qa_shmctl_stat.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< ++ ++qa_shmctl: qa_shmctl.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< ++ ++qa_test: qa_test.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< ++ ++sum16: sum16.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< ++ ++time_stamp: time_stamp.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< ++ ++wrap_int: wrap_int.c ++ rm -f $@ + $(CCF) $(CDEFS) -o $@ $< + + # --- need libpcp +@@ -349,154 +336,867 @@ sizeof: sizeof.c + template: template.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) + + exercise: exercise.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) + + chkacc1: chkacc1.c localconfig.h + rm -f $@ + $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) + + chkacc2: chkacc2.c localconfig.h + rm -f $@ + $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) + + chkacc3: chkacc3.c localconfig.h + rm -f $@ + $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) + + ipc: ipc.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) + + chk_memleak: chk_memleak.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) + + chknumval: chknumval.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) + + logcontrol: logcontrol.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) + + numberstr: numberstr.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) + + pmcdgone: pmcdgone.c localconfig.h + rm -f $@ + $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) + + slow_af: slow_af.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) + + mmv_poke: mmv_poke.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) + + labels: labels.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) + + mergelabels: mergelabels.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) + + mergelabelsets: mergelabelsets.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) + + parselabels: parselabels.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) + + traverse_return_codes: traverse_return_codes.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) + + getdomainname: getdomainname.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) + + pmstrn: pmstrn.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) + + pmfstring: pmfstring.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) + + usergroup: usergroup.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) + + derived_help: derived_help.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) + + derived_control: derived_control.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) + + ready-or-not: ready-or-not.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) + + throttle: throttle.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) + + throttle_timeout: throttle_timeout.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) + + y2038: y2038.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) + + pdu-gadget: pdu-gadget.c myprintresult.o + rm -f $@ + $(CCF) $(CDEFS) -o $@ $< myprintresult.o $(LDLIBS) ++ $(LINKER_MAKERULE) + + strnfoo: strnfoo.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) + + mmv_ondisk: mmv_ondisk.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) + + newcontext: newcontext.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) + + scanindex: scanindex.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) + + localtime: localtime.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) + + unregister: unregister.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) + + genpmns: genpmns.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) + + undelta: undelta.c libpcp.h + rm -f $@ + $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) + + series_time_parse_test: series_time_parse_test.c libpcp.h + rm -f $@ + $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++context_test: context_test.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++chkoptfetch: chkoptfetch.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++archfetch: archfetch.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++779246: 779246.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++addctxdm: addctxdm.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++addlabels: addlabels.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++agenttimeout: agenttimeout.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++aggrstore: aggrstore.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++api_abi: api_abi.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++arch_maxfd: arch_maxfd.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++archctl_segfault: archctl_segfault.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++archend: archend.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++archinst: archinst.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++badloglabel: badloglabel.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++badmmv: badmmv.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++badpmcdpmid: badpmcdpmid.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++badUnitsStr_r: badUnitsStr_r.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++bigpmcdpmids: bigpmcdpmids.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++check_attribute: check_attribute.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++checkstructs: checkstructs.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++chk_metric_types: chk_metric_types.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++chkacc4: chkacc4.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++chkconnect: chkconnect.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++chkctx2: chkctx2.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++chkhelp: chkhelp.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++chklogputresult: chklogputresult.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++chkopenlog: chkopenlog.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++chktrim: chktrim.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++cleanmapdir: cleanmapdir.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++clientid: clientid.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++clienttimeout: clienttimeout.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++compare: compare.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++context_fd_leak: context_fd_leak.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++countmark: countmark.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++crashpmcd: crashpmcd.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++ctx_derive: ctx_derive.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++debug: debug.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++defctx: defctx.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++derived: derived.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++descreqX2: descreqX2.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++disk_test: disk_test.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++drain-server: drain-server.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++eofarch: eofarch.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++eol: eol.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++err: err.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++exectest: exectest.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++exertz: exertz.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++fetchgroup: fetchgroup.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++fetchloop: fetchloop.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++fetchpdu: fetchpdu.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++fetchrate: fetchrate.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++getconfig: getconfig.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++getcontexthost: getcontexthost.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++getoptions: getoptions.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++getversion: getversion.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++github-50: github-50.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++grind_conv: grind_conv.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++hashwalk: hashwalk.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++hex2nbo: hex2nbo.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++hrunpack: hrunpack.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++indom: indom.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++indom2int: indom2int.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++infiniband-umad: infiniband-umad.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++int2indom: int2indom.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++int2pmid: int2pmid.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++interp_bug: interp_bug.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++interp_bug2: interp_bug2.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++interp_bug3: interp_bug3.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++interp0: interp0.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++interp1: interp1.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++interp2: interp2.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++interp3: interp3.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++interp4: interp4.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++loadconfig2: loadconfig2.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++loadderived: loadderived.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++lookupnametest: lookupnametest.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++mark-bug: mark-bug.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++mkfiles: mkfiles.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++multictx: multictx.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++multifetch: multifetch.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++myprintresult: myprintresult.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++nameall: nameall.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++nullinst: nullinst.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++nvidia-ml: nvidia-ml.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++parsehighresinterval: parsehighresinterval.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++parsehostattrs: parsehostattrs.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++parsehostspec: parsehostspec.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++parseinterval: parseinterval.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++parsemetricspec: parsemetricspec.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++pdubufbounds: pdubufbounds.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++permfetch: permfetch.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++pmconvscale: pmconvscale.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++pmfg-derived: pmfg-derived.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++pmid2int: pmid2int.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++pmnsinarchives: pmnsinarchives.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++pmnsunload: pmnsunload.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++pmprintf: pmprintf.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++pmsetmode: pmsetmode.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++pmsocks_objstyle: pmsocks_objstyle.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++pmsprintf: pmsprintf.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++proc_test: proc_test.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++profilecrash: profilecrash.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++progname: progname.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++pv: pv.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++qa_libpcp_compat: qa_libpcp_compat.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++qa_timezone: qa_timezone.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++read-bf: read-bf.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++recon: recon.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++rtimetest: rtimetest.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++scale: scale.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++scandata: scandata.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++scanmeta: scanmeta.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++stampconv: stampconv.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++storepast: storepast.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++storepdu: storepdu.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++storepmcd: storepmcd.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++stripmark: stripmark.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++t_fetch: t_fetch.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++test_service_notify: test_service_notify.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++timeshift: timeshift.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++torture_api: torture_api.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++torture_logmeta: torture_logmeta.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++torture-eol: torture-eol.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++tztest: tztest.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++unpack: unpack.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++unpickargs: unpickargs.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++username: username.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++wait_for_values: wait_for_values.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++whichtimezone: whichtimezone.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++write-bf: write-bf.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++xarch: xarch.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++xlog: xlog.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++xmktime: xmktime.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++xval: xval.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) ++ ++xxx: xxx.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) + + # --- need libpcp but different versions of PMAPI_VERSION and/or + # libpcp.$(DSOSUFFIX) +@@ -505,19 +1205,31 @@ series_time_parse_test: series_time_parse_test.c libpcp.h + getoptions_v2: getoptions.c + rm -f $@ + $(CCF) $(CDEFS) -DPMAPI_VERSION=2 -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) + + api_abi_v2: api_abi.c + rm -f $@ + $(CCF) $(CDEFS) -DPMAPI_VERSION=2 -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) + + # have to play games with libpcp.h so we include the one from + # ../../src/libpcp3/src/include/pcp, not ./libpcp.h ++# ... trap games are to preserve libpcp.h if the compile or ++# $(LINKER_MAKERULE) step fail [thanks coderabbitai], but extra ++# " :" needed after $(LINKER_MAKERULE) to avoid shell ++# Syntax error: ";" unexpected ++# when $(LINKER_MAKERULE) expands to nothing (like everywhere except ++# macOS) + # + api_abi_compat: api_abi.c libpcp.h + rm -f $@ +- mv libpcp.h libpcp.h.save +- $(CC) -I../../src/libpcp3/src/include/pcp $(CFLAGS) $(CDEFS) -o $@ $< ../../src/libpcp3/src/$(LIBPCP3) +- mv libpcp.h.save libpcp.h ++ `set -e; \ ++ mv libpcp.h libpcp.h.save; \ ++ trap 'mv -f libpcp.h.save libpcp.h' 0 1 2 3 15; \ ++ $(CC) -I../../src/libpcp3/src/include/pcp $(CFLAGS) $(CDEFS) -o $@ $< ../../src/libpcp3/src/$(LIBPCP3); \ ++ $(LINKER_MAKERULE) :; \ ++ mv -f libpcp.h.save libpcp.h; \ ++ trap - 0` + + # --- need libpcp but also PM_CONTEXT_LOCAL + # +@@ -525,6 +1237,7 @@ api_abi_compat: api_abi.c libpcp.h + fetchrate_lite: fetchrate_lite.c + rm -f $@ + $(CCF) $(CDEFS) -DLITE=1 -o $@ fetchrate_lite.c $(LDLIBS) ++ $(LINKER_MAKERULE) + + fetchrate_lite.c: fetchrate.c + rm -f $@ +@@ -533,6 +1246,7 @@ fetchrate_lite.c: fetchrate.c + chkctx2_lite: chkctx2_lite.c + rm -f $@ + $(CCF) $(CDEFS) -DLITE=1 -o $@ chkctx2_lite.c $(LDLIBS) ++ $(LINKER_MAKERULE) + + chkctx2_lite.c: chkctx2.c + rm -f $@ +@@ -541,18 +1255,22 @@ chkctx2_lite.c: chkctx2.c + hp-mib: hp-mib.c + rm -f $@ + $(CCF) $(CDEFS) -DLITE=1 -o $@ hp-mib.c $(LDLIBS) ++ $(LINKER_MAKERULE) + + pcp_lite_crash: pcp_lite_crash.c + rm -f $@ + $(CCF) $(CDEFS) -DLITE=1 -o $@ pcp_lite_crash.c $(LDLIBS) ++ $(LINKER_MAKERULE) + + store: store.c + rm -f $@ + $(CCF) $(CDEFS) -DLITE=1 -o $@ store.c $(LDLIBS) ++ $(LINKER_MAKERULE) + + store_and_fetch: store_and_fetch.c + rm -f $@ + $(CCF) $(CDEFS) -DLITE=1 -o $@ store_and_fetch.c $(LDLIBS) ++ $(LINKER_MAKERULE) + + # --- need libpcp_pmda + # +@@ -568,37 +1286,48 @@ domain.h: $(PCP_VAR_DIR)/pmns/stdpmid + pmdashutdown: pmdashutdown.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $@.c $(LDLIBS) -lpcp_pmda ++ $(LINKER_MAKERULE) + + dumb_pmda: dumb_pmda.c localconfig.h + $(CCF) $(LCDEFS) $(LCOPTS) -o $@ $@.c $(LDLIBS) -lpcp_pmda ++ $(LINKER_MAKERULE) + + pmdacache: pmdacache.c + $(CCF) $(LCDEFS) $(LCOPTS) -o $@ $@.c $(LDLIBS) -lpcp_pmda ++ $(LINKER_MAKERULE) + + pmdaqueue: pmdaqueue.c + $(CCF) $(LCDEFS) $(LCOPTS) -o $@ $@.c $(LDLIBS) -lpcp_pmda ++ $(LINKER_MAKERULE) + + rootclient: rootclient.c + $(CCF) $(LCDEFS) $(LCOPTS) -o $@ $@.c $(LDLIBS) -lpcp_pmda ++ $(LINKER_MAKERULE) + + atomstr: atomstr.c + $(CCF) $(LCDEFS) $(LCOPTS) -o $@ $@.c $(LDLIBS) -lpcp_pmda ++ $(LINKER_MAKERULE) + + semstr: semstr.c + $(CCF) $(LCDEFS) $(LCOPTS) -o $@ $@.c $(LDLIBS) -lpcp_pmda ++ $(LINKER_MAKERULE) + + keycache: keycache.c + $(CCF) $(LCDEFS) $(LCOPTS) -o $@ $@.c $(LDLIBS) -lpcp_pmda ++ $(LINKER_MAKERULE) + + keycache2: keycache2.c + $(CCF) $(LCDEFS) $(LCOPTS) -o $@ $@.c $(LDLIBS) -lpcp_pmda ++ $(LINKER_MAKERULE) + + badpmda: badpmda.c + $(CCF) $(LCDEFS) $(LCOPTS) -o $@ $@.c $(LDLIBS) -lpcp_pmda ++ $(LINKER_MAKERULE) + + torture_cache: torture_cache.o + rm -f $@ + $(CCF) $(CDEFS) -o $@ $@.o $(LDLIBS) -lpcp_pmda ++ $(LINKER_MAKERULE) + + # --- need libpcp_gui + # +@@ -606,88 +1335,121 @@ torture_cache: torture_cache.o + record: record.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $@.c $(LDLIBS) -lpcp_gui ++ $(LINKER_MAKERULE) + + record-setarg: record-setarg.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $@.c $(LDLIBS) -lpcp_gui ++ $(LINKER_MAKERULE) + + # --- need libpcp_mmv + # + mmv%: mmv%.o + rm -f $@ + $(CCF) $(CDEFS) -o $@ $@.c $(LDLIBS) -lpcp_mmv ++ $(LINKER_MAKERULE) + + # --- need extra libraries + # + pducheck: pducheck.o + rm -f $@ + $(CCF) $(CDEFS) -o $@ pducheck.o $(TRACELIB) $(LDLIBS) -lpcp_pmda ++ $(LINKER_MAKERULE) + + pducrash: pducrash.o + rm -f $@ + $(CCF) $(CDEFS) -o $@ pducrash.o $(TRACELIB) $(LDLIBS) ++ $(LINKER_MAKERULE) + + pdu-server: pdu-server.o + rm -f $@ + $(CCF) $(CDEFS) -o $@ pdu-server.o $(TRACELIB) $(LDLIBS) ++ $(LINKER_MAKERULE) + + obs: obs.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ obs.c $(TRACELIB) ++ $(LINKER_MAKERULE) + + torture_trace: torture_trace.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ torture_trace.c $(LIB_FOR_PTHREADS) $(TRACELIB) ++ $(LINKER_MAKERULE) + + tstate: tstate.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ tstate.c $(TRACELIB) ++ $(LINKER_MAKERULE) + + tabort: tabort.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ tabort.c $(TRACELIB) ++ $(LINKER_MAKERULE) + + sortinst: sortinst.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ sortinst.c $(LIB_FOR_REGEX) ++ $(LINKER_MAKERULE) + + # --- need libpcp_import + # + ++check_cloexec: check_cloexec.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $@.c $(LDLIBS) ++ $(LINKER_MAKERULE) ++ + check_import: check_import.c + rm -f $@ +- $(CCF) $(CDEFS) -o $@ $@.c $(LDLIBS) -lpcp_import ++ $(CCF) $(CDEFS) -o $@ $@.c $(LDLIBS) -lpcp_archive -lpcp_import ++ $(LINKER_MAKERULE) + + check_import_name: check_import_name.c + rm -f $@ +- $(CCF) $(CDEFS) -o $@ $@.c $(LDLIBS) -lpcp_import ++ $(CCF) $(CDEFS) -o $@ $@.c $(LDLIBS) -lpcp_archive -lpcp_import ++ $(LINKER_MAKERULE) ++ ++check_import_append: check_import_append.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $@.c $(LDLIBS) -lpcp_archive -lpcp_import ++ ++check_volsize: check_volsize.c ++ rm -f $@ ++ $(CCF) $(CDEFS) -o $@ $@.c $(LDLIBS) -lpcp_archive -lpcp_import + + check_pmiend_fdleak: check_pmiend_fdleak.c + rm -f $@ +- $(CCF) $(CDEFS) -o $@ $@.c $(LDLIBS) -lpcp_import ++ $(CCF) $(CDEFS) -o $@ $@.c $(LDLIBS) -lpcp_archive -lpcp_import ++ $(LINKER_MAKERULE) + + check_pmi_errconv: check_pmi_errconv.c + rm -f $@ +- $(CCF) $(CDEFS) -o $@ $@.c $(LDLIBS) -lpcp_import ++ $(CCF) $(CDEFS) -o $@ $@.c $(LDLIBS) -lpcp_archive -lpcp_import ++ $(LINKER_MAKERULE) + + # --- need libpcp_web + # + httpcache: httpcache.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $@.c $(LDLIBS) -lpcp_pmda -lpcp_web -lpcp_mmv ++ $(LINKER_MAKERULE) + + httpfetch: httpfetch.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $@.c $(LDLIBS) -lpcp_pmda -lpcp_web -lpcp_mmv ++ $(LINKER_MAKERULE) + json_test: json_test.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $@.c $(LDLIBS) -lpcp_pmda -lpcp_web -lpcp_mmv ++ $(LINKER_MAKERULE) + sha1int2ext: sha1int2ext.o + rm -f $@ + $(CCF) $(CDEFS) -o $@ $@.c $(LDLIBS) -lpcp_pmda -lpcp_web -lpcp_mmv ++ $(LINKER_MAKERULE) + sha1ext2int: sha1ext2int.o + rm -f $@ + $(CCF) $(CDEFS) -o $@ $@.c $(LDLIBS) -lpcp_pmda -lpcp_web -lpcp_mmv ++ $(LINKER_MAKERULE) + + # --- need libpcp_fault + # +@@ -695,10 +1457,12 @@ sha1ext2int: sha1ext2int.o + check_fault_injection: check_fault_injection.c + rm -f $@ + $(CCF) $(CDEFS) -DPM_FAULT_INJECTION=1 -o $@ $@.c $(LDLIBS) -lpcp_fault -lpcp -lpcp_pmda ++ $(LINKER_MAKERULE) + + exercise_fault: exercise_fault.c + rm -f $@ + $(CCF) $(CDEFS) -DPM_FAULT_INJECTION=1 -o $@ $@.c $(LDLIBS) -lpcp_fault -lpcp -lpcp_pmda ++ $(LINKER_MAKERULE) + + # --- need lib for pthreads + # +@@ -706,71 +1470,88 @@ exercise_fault: exercise_fault.c + multithread0: multithread0.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $@.c $(LIB_FOR_PTHREADS) $(LDLIBS) ++ $(LINKER_MAKERULE) + + multithread1: multithread1.c + rm -f $@ + ifeq "$(TARGET_OS)" "darwin" + @# see comments in multithread1.c to explain this crock + $(CCF) $(CDEFS) -Ddarwin_hack=1 -o $@ $@.c $(LIB_FOR_PTHREADS) -framework CoreFoundation $(LDLIBS) ++ $(LINKER_MAKERULE) + else + $(CCF) $(CDEFS) -o $@ $@.c $(LIB_FOR_PTHREADS) $(LDLIBS) ++ $(LINKER_MAKERULE) + endif + + multithread2: multithread2.c localconfig.h + rm -f $@ + $(CCF) $(CDEFS) -o $@ $@.c $(LIB_FOR_PTHREADS) $(LDLIBS) ++ $(LINKER_MAKERULE) + + multithread3: multithread3.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $@.c $(LIB_FOR_PTHREADS) $(LDLIBS) ++ $(LINKER_MAKERULE) + + multithread4: multithread4.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $@.c $(LIB_FOR_PTHREADS) $(LDLIBS) ++ $(LINKER_MAKERULE) + + multithread5: multithread5.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $@.c $(LIB_FOR_PTHREADS) $(LDLIBS) ++ $(LINKER_MAKERULE) + + multithread6: multithread6.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $@.c $(LIB_FOR_PTHREADS) $(LDLIBS) ++ $(LINKER_MAKERULE) + + multithread7: multithread7.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $@.c $(LIB_FOR_PTHREADS) $(LDLIBS) ++ $(LINKER_MAKERULE) + + multithread8: multithread8.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $@.c $(LIB_FOR_PTHREADS) $(LDLIBS) ++ $(LINKER_MAKERULE) + + multithread9: multithread9.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $@.c $(LIB_FOR_PTHREADS) $(LDLIBS) ++ $(LINKER_MAKERULE) + + multithread10: multithread10.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $@.c $(LIB_FOR_PTHREADS) $(LDLIBS) ++ $(LINKER_MAKERULE) + + multithread11: multithread11.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $@.c $(LIB_FOR_PTHREADS) $(LDLIBS) ++ $(LINKER_MAKERULE) + + multithread12: multithread12.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $@.c $(LIB_FOR_PTHREADS) $(LDLIBS) ++ $(LINKER_MAKERULE) + + multithread13: multithread13.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $@.c $(LIB_FOR_PTHREADS) $(LDLIBS) ++ $(LINKER_MAKERULE) + + multithread14: multithread14.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $@.c $(LIB_FOR_PTHREADS) $(LDLIBS) ++ $(LINKER_MAKERULE) + + exerlock: exerlock.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ $@.c $(LIB_FOR_PTHREADS) $(LDLIBS) ++ $(LINKER_MAKERULE) + + # --- binary format dependencies + # +@@ -778,6 +1559,7 @@ exerlock: exerlock.c + ifeq ($(HAVE_64), 1) + pv64: pv.c + $(CCF) $(CDEFS) -o $@ pv.c $(LDLIBS) ++ $(LINKER_MAKERULE) + else + pv64: + endif +@@ -788,24 +1570,29 @@ endif + torture_indom: torture_indom.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ torture_indom.c $(LDLIBS) ++ $(LINKER_MAKERULE) + + units-parse: units-parse.c + rm -f $@ + $(CCF) $(CDEFS) -o $@ units-parse.c $(LDLIBS) ++ $(LINKER_MAKERULE) + + # --- need add_ctx_dm() + # + grind_ctx: grind_ctx.o addctxdm.o + rm -f $@ + $(CCF) $(CDEFS) -o $@ $^ $(LDLIBS) ++ $(LINKER_MAKERULE) + + churnctx: churnctx.o addctxdm.o + rm -f $@ + $(CCF) $(CDEFS) -o $@ $^ $(LDLIBS) ++ $(LINKER_MAKERULE) + + torture_pmns: torture_pmns.o addctxdm.o + rm -f $@ + $(CCF) $(CDEFS) -o $@ $^ $(LDLIBS) ++ $(LINKER_MAKERULE) + + # --- miscellaneous + # +@@ -839,10 +1626,12 @@ ifeq "$(HAVE_CMOCKA)" "true" + test_encodings: test_encodings.c + rm -f $@ + $(CCF) $(CMOCKACFLAGS) $(CDEFS) -o $@ $^ $(LDLIBS) $(LIB_FOR_CMOCKA) -lpcp_pmda -lpcp_web -lpcp_mmv ++ $(LINKER_MAKERULE) + + test_hostspec: test_hostspec.c + rm -f $@ + $(CCF) $(CMOCKACFLAGS) $(CDEFS) -o $@ $^ $(LDLIBS) $(LIB_FOR_CMOCKA) ++ $(LINKER_MAKERULE) + else + test_encodings: + test_hostspec: +@@ -859,21 +1648,26 @@ dumpstack: dumpstack.c + rm -f $@ + ifeq "$(TOPDIR)" "" + $(CC) -I$(PCP_INC_DIR) -I. $(PCFLAGS) -o $@ -rdynamic $^ -lpcp ++ $(LINKER_MAKERULE) + else + $(CC) -I$(TOPDIR)/src/include -I. $(PCFLAGS) -o $@ -rdynamic $^ -L$(TOPDIR)/src/libpcp/$(LIBPCP_ABIDIR) $(LDLIBS) -lpcp ++ $(LINKER_MAKERULE) + endif + + ifneq ($(NVIDIAQALIB),) + $(NVIDIAQALIB): nvidia-ml.o + $(CC) $(LDFLAGS) $(_SHAREDOPTS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) + endif + + ifneq ($(IBUMADQALIB),) + $(IBUMADQALIB): infiniband-umad.o + $(CC) $(LDFLAGS) $(_SHAREDOPTS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) + + $(IBVERBSQALIB): infiniband-verbs.o + $(CC) $(LDFLAGS) $(_SHAREDOPTS) -o $@ $< $(LDLIBS) ++ $(LINKER_MAKERULE) + endif + + arch_maxfd.o: localconfig.h +@@ -972,6 +1766,8 @@ xmktime.o: libpcp.h + xxx.o: libpcp.h + y2038.o: libpcp.h + ++check_cloexec.o: libpcp.h ++ + bozo: + @echo CFILES_TARGETS=$(CFILES_TARGETS) + @echo "patsubst ->" $(patsubst %.c,%,$(CFILES_TARGETS)) +diff --git a/qa/src/check_cloexec.c b/qa/src/check_cloexec.c +new file mode 100644 +index 0000000000..ebc438d301 +--- /dev/null ++++ b/qa/src/check_cloexec.c +@@ -0,0 +1,38 @@ ++/* ++ * Verify that AF_UNIX sockets created by __pmCreateUnixSocket() ++ * have FD_CLOEXEC set. ++ */ ++ ++#include ++#include "libpcp.h" ++#include ++ ++int ++main(int argc, char **argv) ++{ ++ int fd, flags; ++ ++ pmSetProgname(argv[0]); ++ ++ fd = __pmCreateUnixSocket(); ++ if (fd < 0) { ++ fprintf(stderr, "Error: __pmCreateUnixSocket failed: %s\n", ++ pmErrStr(fd)); ++ return 1; ++ } ++ ++ flags = fcntl(fd, F_GETFD); ++ if (flags < 0) { ++ fprintf(stderr, "Error: fcntl F_GETFD failed\n"); ++ close(fd); ++ return 1; ++ } ++ ++ if (flags & FD_CLOEXEC) ++ printf("FD_CLOEXEC is set\n"); ++ else ++ printf("FAIL: FD_CLOEXEC is NOT set\n"); ++ ++ close(fd); ++ return 0; ++} +diff --git a/src/libpcp/src/auxconnect.c b/src/libpcp/src/auxconnect.c +index 4cac85c147..6e29976b2a 100644 +--- a/src/libpcp/src/auxconnect.c ++++ b/src/libpcp/src/auxconnect.c +@@ -514,8 +514,12 @@ __pmInitSocket(int fd, int family) + } + + #if defined(HAVE_STRUCT_SOCKADDR_UN) +- if (family == AF_UNIX) ++ if (family == AF_UNIX) { ++ int fdFlags; ++ if ((fdFlags = __pmGetFileDescriptorFlags(fd)) >= 0) ++ __pmSetFileDescriptorFlags(fd, fdFlags | FD_CLOEXEC); + return fd; ++ } + #endif + + /* Avoid 200 ms delay. This option is not supported for unix domain sockets. */ +diff --git a/src/libpcp3/src/auxconnect.c b/src/libpcp3/src/auxconnect.c +index 9d82ae539b..3ac64e79aa 100644 +--- a/src/libpcp3/src/auxconnect.c ++++ b/src/libpcp3/src/auxconnect.c +@@ -516,8 +516,12 @@ __pmInitSocket(int fd, int family) + } + + #if defined(HAVE_STRUCT_SOCKADDR_UN) +- if (family == AF_UNIX) ++ if (family == AF_UNIX) { ++ int fdFlags; ++ if ((fdFlags = __pmGetFileDescriptorFlags(fd)) >= 0) ++ __pmSetFileDescriptorFlags(fd, fdFlags | FD_CLOEXEC); + return fd; ++ } + #endif + + /* Avoid 200 ms delay. This option is not supported for unix domain sockets. */ +diff --git a/src/libpcp_pmda/src/root.c b/src/libpcp_pmda/src/root.c +index 06f52b1265..a2897730eb 100644 +--- a/src/libpcp_pmda/src/root.c ++++ b/src/libpcp_pmda/src/root.c +@@ -32,7 +32,7 @@ pmdaRootConnect(const char *path) + char *tmpdir; + char socketpath[MAXPATHLEN]; + char errmsg[PM_MAXERRMSGLEN]; +- int fd, sts, version, features; ++ int fd, sts, version, features, fdFlags; + + /* Initialize the socket address. */ + if ((addr = __pmSockAddrAlloc()) == NULL) +@@ -71,6 +71,9 @@ pmdaRootConnect(const char *path) + return sts; + } + ++ if ((fdFlags = __pmGetFileDescriptorFlags(fd)) >= 0) ++ __pmSetFileDescriptorFlags(fd, fdFlags | FD_CLOEXEC); ++ + /* Check server connection information */ + if ((sts = __pmdaRecvRootPDUInfo(fd, &version, &features)) < 0) { + pmNotifyErr(LOG_ERR, diff --git a/pcp-7.1.5-CVE-2026-16527.patch b/pcp-7.1.5-CVE-2026-16527.patch new file mode 100644 index 0000000..a8de971 --- /dev/null +++ b/pcp-7.1.5-CVE-2026-16527.patch @@ -0,0 +1,197 @@ +From d96ba5a716 Mon Sep 17 00:00:00 2001 +From: Nathan Scott +Subject: [PATCH] pmproxy: fix missing -Q and -S authentication flags (CWE-306) + +The pmproxy -Q (require client certificate) and -S (require +authenticated clients) flags existed as case blocks in the option +parser but were absent from the short_options string and the longopts +table, making them permanently unreachable. An unauthenticated HTTP +client could access all REST API endpoints including /store and /derive. + +Fix: +- Add Q and S to short_options so pmgetopt_r() delivers them +- Add --certreqd and --reqauth entries to the longopts table +- Document both flags in the pmproxy(1) man page +- Add qa/2100 verifying the flags are accepted and that -S correctly + rejects unauthenticated REST API requests with HTTP 403 + +Note: -S enforcement in the REST API path already exists in http.c and +webapi.c. -Q (CERT_REQD) enforcement is only implemented for the +legacy PCP wire protocol path, not the REST API; this is a pre-existing +limitation to be addressed separately. + +Reported-by: Francisco Alisson Bezerra, TIM Security Red Team +Reported-by: Lucas Gabriel Alves, TIM Security Red Team +Reported-by: Massimiliano Brolli, TIM Security Red Team + +Co-Authored-By: Claude Opus 4.6 (1M context) + +Resolves: RHEL-213717 +--- +diff --git a/man/man1/pmproxy.1 b/man/man1/pmproxy.1 +index 6fa0ba94c1..af173edb91 100644 +--- a/man/man1/pmproxy.1 ++++ b/man/man1/pmproxy.1 +@@ -234,6 +234,9 @@ Specify an alternate + number to listen on for client connections. + The default value is 44322. + .TP ++\fB\-Q\f1, \fB\-\-certreqd\f1 ++Require that all client connections provide a trusted client certificate. ++.TP + \f3\-r\f1 \f2port\f1, \f3\-\-keyport\f1=\f2port\f1 + Specify an alternate key-value server + .I port +@@ -248,6 +251,9 @@ The default value is + .IR $PCP_RUN_DIR/pmproxy.socket . + This option implies \f3pmproxy\f1 is running in \f3timeseries\f1 mode. + .TP ++\fB\-S\f1, \fB\-\-reqauth\f1 ++Require that all client connections be authenticated. ++.TP + \fB\-t\f1, \fB\-\-timeseries\f1 + Operate in automatic archive timeseries discovery mode. + This mode of operation will enable the +diff --git a/qa/2100 b/qa/2100 +new file mode 100755 +index 0000000000..1de957a2f1 +--- /dev/null ++++ b/qa/2100 +@@ -0,0 +1,85 @@ ++#!/bin/sh ++# PCP QA Test No. 2100 ++# Verify pmproxy -Q and -S authentication flags are accepted ++# and that -S (reqauth) enforces authentication on REST API ++# ++# Copyright (c) 2026 Red Hat. All Rights Reserved. ++# ++ ++seq=`basename $0` ++echo "QA output created by $seq" ++ ++# get standard environment, filters and checks ++. ./common.product ++. ./common.filter ++. ./common.check ++ ++which curl >/dev/null 2>&1 || _notrun "no curl executable installed" ++ ++_cleanup() ++{ ++ [ -n "$__pid" ] && kill $__pid 2>/dev/null ++ wait $__pid 2>/dev/null ++ cd $here ++ $sudo rm -rf $tmp $tmp.* ++} ++ ++status=0 # success is the default! ++__pid="" ++trap "_cleanup; exit \$status" 0 1 2 3 15 ++ ++# real QA test starts here ++ ++echo "=== checking -Q and -S appear in usage ===" ++pmproxy --help 2>&1 | grep -E '\-[QS]' | sed -e 's/^ *//' ++ ++echo ++echo "=== checking -S enforces authentication on REST API ===" ++__port=`_find_free_port` ++$PCP_BINADM_DIR/pmproxy -S -f -p $__port -l $tmp.log & ++__pid=$! ++sleep 1 ++if kill -0 $__pid 2>/dev/null; then ++ echo "pmproxy with -S started" ++ ++ # unauthenticated request should be rejected ++ __code=`curl -s -o /dev/null -w '%{http_code}' "http://localhost:$__port/pmapi/context?hostspec=localhost" 2>/dev/null` ++ if [ "$__code" = "403" ]; then ++ echo "unauthenticated request correctly rejected (HTTP $__code)" ++ else ++ echo "FAIL: expected HTTP 403, got HTTP $__code" ++ fi ++ ++ kill $__pid ++ wait $__pid 2>/dev/null ++ __pid="" ++else ++ echo "FAIL: pmproxy with -S did not start" ++fi ++ ++echo ++echo "=== checking without -S allows unauthenticated access ===" ++__port=`_find_free_port` ++$PCP_BINADM_DIR/pmproxy -f -p $__port -l $tmp.log2 & ++__pid=$! ++sleep 1 ++if kill -0 $__pid 2>/dev/null; then ++ echo "pmproxy without -S started" ++ ++ # unauthenticated request should succeed ++ __code=`curl -s -o /dev/null -w '%{http_code}' "http://localhost:$__port/pmapi/context?hostspec=localhost" 2>/dev/null` ++ if [ "$__code" = "200" ]; then ++ echo "unauthenticated request correctly allowed (HTTP $__code)" ++ else ++ echo "FAIL: expected HTTP 200, got HTTP $__code" ++ fi ++ ++ kill $__pid ++ wait $__pid 2>/dev/null ++ __pid="" ++else ++ echo "FAIL: pmproxy without -S did not start" ++fi ++ ++# success, all done ++exit +diff --git a/qa/2100.out b/qa/2100.out +new file mode 100644 +index 0000000000..5302aea77a +--- /dev/null ++++ b/qa/2100.out +@@ -0,0 +1,12 @@ ++QA output created by 2100 ++=== checking -Q and -S appear in usage === ++-Q, --certreqd require client certificate authentication ++-S, --reqauth require all client connections to be authenticated ++ ++=== checking -S enforces authentication on REST API === ++pmproxy with -S started ++unauthenticated request correctly rejected (HTTP 403) ++ ++=== checking without -S allows unauthenticated access === ++pmproxy without -S started ++unauthenticated request correctly allowed (HTTP 200) +diff --git a/qa/group b/qa/group +index 3590d90dc2..92c27dc49f 100644 +--- a/qa/group ++++ b/qa/group +@@ -2373,5 +2373,6 @@ suse + 1998 pmda.rds local python + 2106 pmproxy local security + 2105 libpcp pmcd local security pmcd.pdu ++2100 pmproxy local security + 4751 libpcp threads valgrind local pcp helgrind + 9000 other local +diff --git a/src/pmproxy/src/pmproxy.c b/src/pmproxy/src/pmproxy.c +index ce2a9ebf53..5db0d5fdb9 100644 +--- a/src/pmproxy/src/pmproxy.c ++++ b/src/pmproxy/src/pmproxy.c +@@ -82,7 +82,9 @@ static pmLongOptions longopts[] = { + PMAPI_OPTIONS_HEADER("Connection options"), + { "interface", 1, 'i', "ADDR", "accept connections on this IP address" }, + { "port", 1, 'p', "PORT", "accept connections on this port" }, ++ { "certreqd", 0, 'Q', 0, "require client certificate authentication" }, + { "socket", 1, 's', "PATH", "Unix domain socket file [default $PCP_RUN_DIR/pmproxy.socket]" }, ++ { "reqauth", 0, 'S', 0, "require all client connections to be authenticated" }, + { "keyport", 1, 'r', "PORT", "Connect to key server on this TCP/IP port (implies --timeseries)" }, + { "keyhost", 1, 'h', "HOST", "Connect to key server on this host name (implies --timeseries)" }, + { "redisport", 1, 'r', "PORT", "Backwards-compatibility option, do not use" }, +@@ -95,7 +97,7 @@ static pmLongOptions longopts[] = { + }; + + static pmOptions opts = { +- .short_options = "Ac:dD:Ffh:i:l:L:p:r:s:tT:U:x:?", ++ .short_options = "Ac:dD:Ffh:i:l:L:p:Qr:s:StT:U:x:?", + .long_options = longopts, + }; + diff --git a/pcp-7.1.5-CVE-2026-16529.patch b/pcp-7.1.5-CVE-2026-16529.patch new file mode 100644 index 0000000..58f2f8a --- /dev/null +++ b/pcp-7.1.5-CVE-2026-16529.patch @@ -0,0 +1,149 @@ +From ef848fb978 Mon Sep 17 00:00:00 2001 +From: Nathan Scott +Subject: [PATCH] libpcp: fix integer overflow in __pmGetPDU() (CWE-190) + +When php->len is near INT_MAX (e.g. 0x7FFFFFFF), the buffer size +computation PDU_CHUNK * (1 + php->len / PDU_CHUNK) overflows signed +int, producing a negative value that permanently corrupts the static +maxsize variable. Every subsequent __pmFindPDUBuf() call returns NULL, +rendering the affected daemon (pmlogger, pmcd) unable to process any +further PDUs for the remainder of its lifetime — a persistent denial +of service requiring a restart. + +Fix: add an overflow guard (php->len > INT_MAX - PDU_CHUNK) before +the multiplication, returning PM_ERR_TOOBIG for absurdly large PDU +lengths. This protects the NO_LIMIT code path used by pmcd and +pmlogger that is not covered by the existing ceiling check. + +Also add _filter_pmcd() to qa/common.pmcd.pdu to normalize fd=N in +pmcd log output, and qa/2105 with a crafted PDU exercising the +overflow. + +Reported-by: Francisco Alisson Bezerra, TIM Security Red Team +Reported-by: Lucas Gabriel Alves, TIM Security Red Team +Reported-by: Massimiliano Brolli, TIM Security Red Team + +Co-Authored-By: Claude Opus 4.6 (1M context) + +Resolves: RHEL-213726 +--- +diff --git a/qa/2105 b/qa/2105 +new file mode 100755 +index 0000000000..44b849ad39 +--- /dev/null ++++ b/qa/2105 +@@ -0,0 +1,17 @@ ++#!/bin/sh ++# PCP QA Test No. 2105 ++# Verify __pmGetPDU rejects PDU with len near INT_MAX ++# (integer overflow in buffer size computation, CWE-190) ++# ++# Copyright (c) 2026 Red Hat. All Rights Reserved. ++# ++ ++seq=`basename $0` ++echo "QA output created by $seq" ++ ++pdu_data=pdudata/pdu-getpdu-overflow ++grep_pattern="bad PDU len=.*exceeds maximum|PDU len=.*too large" ++ ++# this is one of the generic pmcd PDU exerciser tests ... ++# ++. ./common.pmcd.pdu +diff --git a/qa/2105.out b/qa/2105.out +new file mode 100644 +index 0000000000..a304f9d913 +--- /dev/null ++++ b/qa/2105.out +@@ -0,0 +1,10 @@ ++QA output created by 2105 ++expect error(s) to be logged ... ++__pmGetPDU: fd=N type=0x8000 bad PDU len=2147483647 in hdr exceeds maximum client PDU size (65536) ++ ++and no valgrind badness ... ++Memcheck, a memory error detector ++LEAK SUMMARY: ++definitely lost: 0 bytes in 0 blocks ++indirectly lost: 0 bytes in 0 blocks ++ERROR SUMMARY: 0 errors from 0 contexts ... +diff --git a/qa/common.pmcd.pdu b/qa/common.pmcd.pdu +index 4ab98775e0..8fa832aa82 100644 +--- a/qa/common.pmcd.pdu ++++ b/qa/common.pmcd.pdu +@@ -54,6 +54,14 @@ _filter() + # end + } + ++_filter_pmcd() ++{ ++ sed \ ++ -e 's/fd=[0-9][0-9]*/fd=N/g' \ ++ -e 's/^\[.*\] pmcd([0-9]*) [A-Za-z]*: //' \ ++ # end ++} ++ + mkdir $tmp || exit 1 + cd $tmp + grep sampledso $PCP_PMCDCONF_PATH >pmcd.conf +@@ -90,7 +98,7 @@ wait + [ -s $tmp.err ] && cat $tmp.err + + echo "expect error(s) to be logged ..." +-grep -E "$grep_pattern" pmcd.log ++grep -E "$grep_pattern" pmcd.log | _filter_pmcd + + echo + echo "and no valgrind badness ..." +diff --git a/qa/group b/qa/group +index 51e9e4d761..3590d90dc2 100644 +--- a/qa/group ++++ b/qa/group +@@ -2372,5 +2372,6 @@ suse + 1997 pcp nfsiostat python local + 1998 pmda.rds local python + 2106 pmproxy local security ++2105 libpcp pmcd local security pmcd.pdu + 4751 libpcp threads valgrind local pcp helgrind + 9000 other local +diff --git a/qa/pdudata/pdu-getpdu-overflow b/qa/pdudata/pdu-getpdu-overflow +new file mode 100644 +index 0000000000..5e57cd4b7a +Binary files /dev/null and b/qa/pdudata/pdu-getpdu-overflow differ +diff --git a/src/libpcp/src/pdu.c b/src/libpcp/src/pdu.c +index 5845932be1..0a4ae75b25 100644 +--- a/src/libpcp/src/pdu.c ++++ b/src/libpcp/src/pdu.c +@@ -658,6 +658,14 @@ check_read_len: + + PM_LOCK(pdu_lock); + if (php->len > maxsize) { ++ if (php->len > INT_MAX - PDU_CHUNK) { ++ PM_UNLOCK(pdu_lock); ++ if (pmDebugOptions.pdu) ++ pmNotifyErr(LOG_ERR, "%s: fd=%d PDU len=%d too large", ++ __FUNCTION__, fd, php->len); ++ __pmUnpinPDUBuf(pdubuf); ++ return PM_ERR_TOOBIG; ++ } + tmpsize = PDU_CHUNK * ( 1 + php->len / PDU_CHUNK); + maxsize = tmpsize; + } +diff --git a/src/libpcp3/src/pdu.c b/src/libpcp3/src/pdu.c +index 5845932be1..0a4ae75b25 100644 +--- a/src/libpcp3/src/pdu.c ++++ b/src/libpcp3/src/pdu.c +@@ -658,6 +658,14 @@ check_read_len: + + PM_LOCK(pdu_lock); + if (php->len > maxsize) { ++ if (php->len > INT_MAX - PDU_CHUNK) { ++ PM_UNLOCK(pdu_lock); ++ if (pmDebugOptions.pdu) ++ pmNotifyErr(LOG_ERR, "%s: fd=%d PDU len=%d too large", ++ __FUNCTION__, fd, php->len); ++ __pmUnpinPDUBuf(pdubuf); ++ return PM_ERR_TOOBIG; ++ } + tmpsize = PDU_CHUNK * ( 1 + php->len / PDU_CHUNK); + maxsize = tmpsize; + } diff --git a/pcp.spec b/pcp.spec index 8efa43e..bc6e766 100644 --- a/pcp.spec +++ b/pcp.spec @@ -1,6 +1,6 @@ Name: pcp Version: 7.1.5 -Release: 4%{?dist} +Release: 5%{?dist} Summary: System-level performance monitoring and performance management License: GPL-2.0-or-later AND LGPL-2.1-or-later AND CC-BY-3.0 URL: https://pcp.io @@ -19,6 +19,22 @@ Patch0: pcp-7.1.5-CVE-2026-16530.patch # https://github.com/performancecopilot/pcp/commit/dd6ed05f143f97e00198cb4b0180c6375d758cbe Patch1: pcp-7.1.5-CVE-2026-16531.patch +# https://issues.redhat.com/browse/RHEL-213726 +# https://github.com/performancecopilot/pcp/commit/ef848fb978d26335f9676933f541c73b58f130a6 +Patch2: pcp-7.1.5-CVE-2026-16529.patch + +# https://issues.redhat.com/browse/RHEL-213717 +# https://github.com/performancecopilot/pcp/commit/d96ba5a716eeff7840138eb08fbab0d11a57f641 +Patch3: pcp-7.1.5-CVE-2026-16527.patch + +# https://issues.redhat.com/browse/RHEL-213692 +# https://github.com/performancecopilot/pcp/commit/7e27614006ff6fc4925991edbedaf1eab6b14731 +Patch4: pcp-7.1.5-CVE-2026-16526.patch + +# https://issues.redhat.com/browse/RHEL-213661 +# https://github.com/performancecopilot/pcp/commit/c5cbeceb7d3c2af357c04065cdd911efdc270de0 +Patch5: pcp-7.1.5-CVE-2026-16524.patch + # The additional linker flags break out-of-tree PMDAs. # https://bugzilla.redhat.com/show_bug.cgi?id=2043092 %undefine _package_note_flags @@ -3432,6 +3448,12 @@ fi %files zeroconf -f pcp-zeroconf-files.rpm %changelog +* Wed Aug 12 2026 Jan Kuřík - 7.1.5-5 +- Fix CVE-2026-16524: linux_sockets PMDA command injection (RHEL-213661) +- Fix CVE-2026-16526: FD_CLOEXEC privilege escalation via pmdaroot (RHEL-213692) +- Fix CVE-2026-16527: pmproxy unauthenticated /store access (RHEL-213717) +- Fix CVE-2026-16529: __pmGetPDU signed integer overflow DoS (RHEL-213726) + * Thu Jul 30 2026 RHEL Packaging Agent - 7.1.5-4 - Fix CVE-2026-16531: path traversal via hostname in pmproxy (RHEL-213756)