diff --git a/SOURCES/no-more-log4j.patch b/SOURCES/no-more-log4j.patch
new file mode 100644
index 0000000..88008ea
--- /dev/null
+++ b/SOURCES/no-more-log4j.patch
@@ -0,0 +1,283 @@
+diff -Naurp parfait-0.5.4.orig/parfait-agent/pom.xml parfait-0.5.4/parfait-agent/pom.xml
+--- parfait-0.5.4.orig/parfait-agent/pom.xml 2017-10-11 11:01:37.000000000 +1100
++++ parfait-0.5.4/parfait-agent/pom.xml 2021-12-16 14:46:17.702813590 +1100
+@@ -142,11 +142,6 @@
+ ${slf4j.version}
+
+
+- log4j
+- log4j
+- ${log4j.version}
+-
+-
+ com.fasterxml.jackson.core
+ jackson-core
+ 2.8.8
+diff -Naurp parfait-0.5.4.orig/parfait-agent/src/main/java/io/pcp/parfait/AgentMonitoringView.java parfait-0.5.4/parfait-agent/src/main/java/io/pcp/parfait/AgentMonitoringView.java
+--- parfait-0.5.4.orig/parfait-agent/src/main/java/io/pcp/parfait/AgentMonitoringView.java 2017-10-11 11:01:37.000000000 +1100
++++ parfait-0.5.4/parfait-agent/src/main/java/io/pcp/parfait/AgentMonitoringView.java 2021-12-16 14:46:17.702813590 +1100
+@@ -48,11 +48,12 @@ import javax.management.ReflectionExcept
+ import javax.management.openmbean.CompositeData;
+ import javax.measure.Unit;
+
+-import org.apache.log4j.Logger;
++import org.slf4j.Logger;
++import org.slf4j.LoggerFactory;
+
+
+ class AgentMonitoringView {
+- private static final Logger logger = Logger.getLogger(ParfaitAgent.class);
++ private static final Logger logger = LoggerFactory.getLogger(ParfaitAgent.class);
+
+ private MonitorableRegistry registry = MonitorableRegistry.DEFAULT_REGISTRY;
+
+diff -Naurp parfait-0.5.4.orig/parfait-agent/src/main/java/io/pcp/parfait/JmxUtilities.java parfait-0.5.4/parfait-agent/src/main/java/io/pcp/parfait/JmxUtilities.java
+--- parfait-0.5.4.orig/parfait-agent/src/main/java/io/pcp/parfait/JmxUtilities.java 2017-10-11 11:01:37.000000000 +1100
++++ parfait-0.5.4/parfait-agent/src/main/java/io/pcp/parfait/JmxUtilities.java 2021-12-16 14:46:17.703813573 +1100
+@@ -29,8 +29,6 @@ import javax.management.remote.JMXConnec
+ import javax.management.remote.JMXConnectorFactory;
+ import javax.management.remote.JMXServiceURL;
+
+-import org.apache.log4j.Logger;
+-
+ /**
+ * Convenience mechanisms for locating MBeanServer classes.
+ */
+diff -Naurp parfait-0.5.4.orig/parfait-agent/src/main/java/io/pcp/parfait/ParfaitAgent.java parfait-0.5.4/parfait-agent/src/main/java/io/pcp/parfait/ParfaitAgent.java
+--- parfait-0.5.4.orig/parfait-agent/src/main/java/io/pcp/parfait/ParfaitAgent.java 2017-10-11 11:01:37.000000000 +1100
++++ parfait-0.5.4/parfait-agent/src/main/java/io/pcp/parfait/ParfaitAgent.java 2021-12-16 14:49:54.874103371 +1100
+@@ -42,10 +42,11 @@ import javax.management.IntrospectionExc
+ import javax.management.MBeanException;
+ import javax.management.MBeanServer;
+
+-import org.apache.log4j.Logger;
++import org.slf4j.Logger;
++import org.slf4j.LoggerFactory;
+
+ public class ParfaitAgent {
+- private static final Logger logger = Logger.getLogger(ParfaitAgent.class);
++ private static final Logger logger = LoggerFactory.getLogger(ParfaitAgent.class);
+
+ private static final String RESOURCE = "/jvm.json";
+ private static final String PATHNAME = "/etc/parfait";
+diff -Naurp parfait-0.5.4.orig/parfait-core/src/main/java/io/pcp/parfait/QuiescentRegistryListener.java parfait-0.5.4/parfait-core/src/main/java/io/pcp/parfait/QuiescentRegistryListener.java
+--- parfait-0.5.4.orig/parfait-core/src/main/java/io/pcp/parfait/QuiescentRegistryListener.java 2017-10-11 11:01:37.000000000 +1100
++++ parfait-0.5.4/parfait-core/src/main/java/io/pcp/parfait/QuiescentRegistryListener.java 2021-12-16 14:46:17.703813573 +1100
+@@ -20,14 +20,15 @@ import java.util.Timer;
+ import java.util.TimerTask;
+
+ import com.google.common.base.Supplier;
+-import org.apache.log4j.Logger;
++import org.slf4j.Logger;
++import org.slf4j.LoggerFactory;
+
+ /**
+ * Designed to run code after the MonitorableRegistry has become quiet, in terms of addition of new metrics
+ */
+ public class QuiescentRegistryListener implements MonitorableRegistryListener {
+
+- private static final Logger LOG = Logger.getLogger(QuiescentRegistryListener.class);
++ private static final Logger LOG = LoggerFactory.getLogger(QuiescentRegistryListener.class);
+
+ private final Scheduler quiescentScheduler;
+ private volatile long lastTimeMonitorableAdded = 0;
+diff -Naurp parfait-0.5.4.orig/parfait-core/src/main/java/io/pcp/parfait/timing/ThreadContext.java parfait-0.5.4/parfait-core/src/main/java/io/pcp/parfait/timing/ThreadContext.java
+--- parfait-0.5.4.orig/parfait-core/src/main/java/io/pcp/parfait/timing/ThreadContext.java 2021-12-16 14:45:29.312640302 +1100
++++ parfait-0.5.4/parfait-core/src/main/java/io/pcp/parfait/timing/ThreadContext.java 2021-12-16 14:46:17.703813573 +1100
+@@ -95,11 +95,6 @@ public class ThreadContext {
+ * Clears all values for the current thread.
+ */
+ public void clear() {
+-
+- /**
+- * Unfortunately log4j's MDC historically never had a mechanism to block remove keys,
+- * so we're forced to do this one by one.
+- */
+ for (String key : allKeys()) {
+ mdcBridge.remove(key);
+ }
+@@ -127,21 +122,18 @@ public class ThreadContext {
+ }
+
+ /**
+- * Factory method that creates a new ThreadContext initialized to also update Log4j's MDC.
++ * Factory methods that create a new ThreadContext initialised to also update SLF4J's MDC
+ */
+ public static ThreadContext newMDCEnabledContext() {
+- return new ThreadContext(new Log4jMdcBridge());
++ return newSLF4JEnabledContext();
+ }
+
+- /**
+- * Factory method that creates a new ThreadContext initialised to also update SLF4J's MDC
+- */
+ public static ThreadContext newSLF4JEnabledContext() {
+ return new ThreadContext(new Slf4jMDCBridge());
+ }
+
+ public interface MdcBridge {
+- void put(String key, Object object);
++ void put(String key, Object object);
+
+ void remove(String key);
+ }
+@@ -158,18 +150,6 @@ public class ThreadContext {
+ }
+ }
+
+- public static class Log4jMdcBridge implements MdcBridge {
+- @Override
+- public void put(String key, Object object) {
+- org.apache.log4j.MDC.put(key, object);
+- }
+-
+- @Override
+- public void remove(String key) {
+- org.apache.log4j.MDC.remove(key);
+- }
+- }
+-
+ public static class Slf4jMDCBridge implements MdcBridge {
+ @Override
+ public void put(String key, Object object) {
+diff -Naurp parfait-0.5.4.orig/parfait-core/src/test/java/io/pcp/parfait/timing/ThreadContextTest.java parfait-0.5.4/parfait-core/src/test/java/io/pcp/parfait/timing/ThreadContextTest.java
+--- parfait-0.5.4.orig/parfait-core/src/test/java/io/pcp/parfait/timing/ThreadContextTest.java 2017-10-11 11:01:37.000000000 +1100
++++ parfait-0.5.4/parfait-core/src/test/java/io/pcp/parfait/timing/ThreadContextTest.java 2021-12-16 14:46:17.703813573 +1100
+@@ -20,7 +20,7 @@ import java.util.Hashtable;
+ import java.util.Map;
+ import java.util.concurrent.CountDownLatch;
+
+-import org.apache.log4j.MDC;
++import org.slf4j.MDC;
+
+ import junit.framework.TestCase;
+
+@@ -29,11 +29,7 @@ public class ThreadContextTest extends T
+
+ public void setUp() {
+ context = new ThreadContext();
+-
+- Hashtable hashtable = MDC.getContext();
+- if (hashtable != null) {
+- hashtable.clear();
+- }
++ MDC.clear();
+ }
+
+
+@@ -86,15 +82,16 @@ public class ThreadContextTest extends T
+ assertNull("get() after clear should return null", context.get(testKey));
+ }
+
++/* -- Slf4j provides no MDC context API --
+ public void testClearRemovesMDCValue() {
+
+- ThreadContext log4jThreadContext = ThreadContext.newMDCEnabledContext();
++ ThreadContext logThreadContext = ThreadContext.newMDCEnabledContext();
+
+ Hashtable mdcContext = MDC.getContext();
+ assertTrue(mdcContext == null || mdcContext.isEmpty());
+
+ final String testKey = "painter";
+- log4jThreadContext.put(testKey, 7);
++ logThreadContext.put(testKey, 7);
+
+ mdcContext = MDC.getContext();
+ assertEquals(1, mdcContext.size());
+@@ -102,7 +99,8 @@ public class ThreadContextTest extends T
+ mdcContext.clear();
+ assertEquals(0, mdcContext.size());
+
+- log4jThreadContext.clear();
+- assertNull("get() after clear should return null", log4jThreadContext.get(testKey));
++ logThreadContext.clear();
++ assertNull("get() after clear should return null", logThreadContext.get(testKey));
+ }
++*/
+ }
+diff -Naurp parfait-0.5.4.orig/pom.xml parfait-0.5.4/pom.xml
+--- parfait-0.5.4.orig/pom.xml 2021-12-16 14:45:29.313640285 +1100
++++ parfait-0.5.4/pom.xml 2021-12-16 14:50:31.701474201 +1100
+@@ -95,7 +95,6 @@
+ UTF-8
+ 4.2.5.RELEASE
+ 1.6.1
+- 1.2.14
+ 1.8
+ ${jdk.version}
+ ${jdk.version}
+@@ -323,11 +322,6 @@
+ org.slf4j
+ slf4j-api
+ ${slf4j.version}
+-
+-
+- log4j
+- log4j
+- ${log4j.version}
+
+
+ com.google.guava
+@@ -385,11 +379,6 @@
+ slf4j-api
+
+
+- log4j
+- log4j
+- true
+-
+-
+ com.fasterxml.jackson.core
+ jackson-core
+ 2.8.8
+diff -Naurp parfait-0.5.4.orig/parfait-agent/src/main/resources/log4j2.xml parfait-0.5.4/parfait-agent/src/main/resources/log4j2.xml
+--- parfait-0.5.4.orig/parfait-agent/src/main/resources/log4j2.xml 2022-01-10 17:09:09.794017829 +0100
++++ parfait-0.5.4/parfait-agent/src/main/resources/log4j2.xml 1970-01-01 01:00:00.000000000 +0100
+@@ -1,36 +0,0 @@
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+-
+diff -Naurp parfait-0.5.4.orig/parfait-agent/src/main/resources/log4j.properties parfait-0.5.4/parfait-agent/src/main/resources/log4j.properties
+--- parfait-0.5.4.orig/parfait-agent/src/main/resources/log4j.properties 2022-01-10 17:09:09.794017829 +0100
++++ parfait-0.5.4/parfait-agent/src/main/resources/log4j.properties 1970-01-01 01:00:00.000000000 +0100
+@@ -1,7 +0,0 @@
+-# Set root logger level to ERROR and its only appender to A1.
+-log4j.rootLogger=warn, A1
+-
+-log4j.appender.A1=org.apache.log4j.ConsoleAppender
+-log4j.appender.A1.Threshold=warn
+-log4j.appender.A1.layout=org.apache.log4j.PatternLayout
+-log4j.appender.A1.layout.ConversionPattern=[%t] %-5p %c %x - %m%n
diff --git a/SPECS/parfait.spec b/SPECS/parfait.spec
index bd1c763..fc0cba5 100644
--- a/SPECS/parfait.spec
+++ b/SPECS/parfait.spec
@@ -1,6 +1,6 @@
Name: parfait
Version: 0.5.4
-Release: 2%{?dist}
+Release: 4%{?dist}
Summary: Java libraries for Performance Co-Pilot (PCP)
License: ASL 2.0
URL: https://github.com/performancecopilot/parfait
@@ -8,6 +8,7 @@ Source0: https://github.com/performancecopilot/parfait/archive/%{version}/
Patch1: no-jcip-annotations.patch
Patch2: no-more-objects.patch
+Patch3: no-more-log4j.patch
%bcond_with metrics
@@ -56,6 +57,13 @@ BuildRequires: mvn(tec.uom:uom-se)
BuildArch: noarch
+# parfait used to have a dependency on log4j12. Since parfait 0.5.4-3, log4j is no longer a dependency.
+# This line makes sure that the log4j12 package will be removed when upgrading
+# to parfait 0.5.4-4, to remove all vulnerable log4j12 versions (CVE-2021-4104).
+# Also matches NVR 1.2.17-22.module+el8+...
+Obsoletes: log4j12 < 1.2.17-23
+Obsoletes: log4j12-javadoc < 1.2.17-23
+
%description
Parfait is a Java performance monitoring library that exposes and
collects metrics through a variety of outputs. It provides APIs
@@ -95,6 +103,7 @@ for instrumenting applications.
%if 0%{?rhel} != 0
%patch1 -p1
%patch2 -p1
+%patch3 -p1
%endif
# Remove license plugin in main pom.xml
@@ -175,6 +184,13 @@ done
%config(noreplace)%{_sysconfdir}/%{name}/jvm.json
%changelog
+* Tue Jan 18 2022 Andreas Gerstmayr - 0.5.4-4
+- Obsolete (remove) vulnerable versions of log4j12 (NVR < 1.2.17-23)
+ when upgrading to parfait 0.5.4-4 (CVE-2021-4104)
+
+* Thu Dec 16 2021 Nathan Scott - 0.5.4-3
+- Drop all code explicitly using Log4J (BZ 2032158)
+
* Wed Nov 01 2017 Nathan Scott - 0.5.4-2
- Install a default configuration file for base JVM metrics.