Blame SOURCES/0001-Fix-CVE-2022-1471-and-add-a-test.patch

a9ab27
From fa99814967c44e654aae64802947209e2817359f Mon Sep 17 00:00:00 2001
a9ab27
From: Severin Gehwolf <sgehwolf@redhat.com>
a9ab27
Date: Tue, 6 Dec 2022 17:32:30 +0100
a9ab27
Subject: [PATCH] Fix CVE-2022-1471 and add a test
a9ab27
a9ab27
---
a9ab27
 .../java/io/prometheus/jmx/JmxCollector.java  | 34 +++++++++----
a9ab27
 .../io/prometheus/jmx/JmxCollectorTest.java   | 51 +++++++++++++++++++
a9ab27
 .../test/java/io/prometheus/jmx/Person.java   | 38 ++++++++++++++
a9ab27
 .../test/resources/testyaml_javabean.config   |  6 +++
a9ab27
 4 files changed, 119 insertions(+), 10 deletions(-)
a9ab27
 create mode 100644 collector/src/test/java/io/prometheus/jmx/Person.java
a9ab27
 create mode 100644 collector/src/test/resources/testyaml_javabean.config
a9ab27
a9ab27
diff --git a/collector/src/main/java/io/prometheus/jmx/JmxCollector.java b/collector/src/main/java/io/prometheus/jmx/JmxCollector.java
a9ab27
index a5fc96f..38f13ed 100644
a9ab27
--- a/collector/src/main/java/io/prometheus/jmx/JmxCollector.java
a9ab27
+++ b/collector/src/main/java/io/prometheus/jmx/JmxCollector.java
a9ab27
@@ -1,12 +1,7 @@
a9ab27
 package io.prometheus.jmx;
a9ab27
 
a9ab27
-import io.prometheus.client.Collector;
a9ab27
-import io.prometheus.client.Counter;
a9ab27
-import org.yaml.snakeyaml.Yaml;
a9ab27
-import org.yaml.snakeyaml.error.YAMLException;
a9ab27
+import static java.lang.String.format;
a9ab27
 
a9ab27
-import javax.management.MalformedObjectNameException;
a9ab27
-import javax.management.ObjectName;
a9ab27
 import java.io.File;
a9ab27
 import java.io.FileReader;
a9ab27
 import java.io.IOException;
a9ab27
@@ -25,7 +20,19 @@ import java.util.logging.Logger;
a9ab27
 import java.util.regex.Matcher;
a9ab27
 import java.util.regex.Pattern;
a9ab27
 
a9ab27
-import static java.lang.String.format;
a9ab27
+import javax.management.MalformedObjectNameException;
a9ab27
+import javax.management.ObjectName;
a9ab27
+
a9ab27
+import org.yaml.snakeyaml.DumperOptions;
a9ab27
+import org.yaml.snakeyaml.LoaderOptions;
a9ab27
+import org.yaml.snakeyaml.Yaml;
a9ab27
+import org.yaml.snakeyaml.constructor.SafeConstructor;
a9ab27
+import org.yaml.snakeyaml.error.YAMLException;
a9ab27
+import org.yaml.snakeyaml.representer.Representer;
a9ab27
+import org.yaml.snakeyaml.resolver.Resolver;
a9ab27
+
a9ab27
+import io.prometheus.client.Collector;
a9ab27
+import io.prometheus.client.Counter;
a9ab27
 
a9ab27
 public class JmxCollector extends Collector implements Collector.Describable {
a9ab27
     static final Counter configReloadSuccess = Counter.build()
a9ab27
@@ -76,7 +83,7 @@ public class JmxCollector extends Collector implements Collector.Describable {
a9ab27
         // will be thrown for bad configs
a9ab27
         Map<String, Object> yamlConfig = null;
a9ab27
         try {
a9ab27
-            yamlConfig = (Map<String, Object>)new Yaml().load(new FileReader(in));
a9ab27
+            yamlConfig = (Map<String, Object>)createYamlInstance().load(new FileReader(in));
a9ab27
         } catch (YAMLException e) {
a9ab27
             System.err.println("YAML configuration error: " + e.getMessage());
a9ab27
             throw new IllegalArgumentException(e);
a9ab27
@@ -86,7 +93,14 @@ public class JmxCollector extends Collector implements Collector.Describable {
a9ab27
     }
a9ab27
 
a9ab27
     public JmxCollector(String yamlConfig) throws MalformedObjectNameException {
a9ab27
-        config = loadConfig((Map<String, Object>)new Yaml().load(yamlConfig));
a9ab27
+        config = loadConfig((Map<String, Object>)createYamlInstance().load(yamlConfig));
a9ab27
+    }
a9ab27
+
a9ab27
+    private static Yaml createYamlInstance() {
a9ab27
+        // Equivalent to default Yaml() constructor but using SafeConstructor()
a9ab27
+        // over Constructor();
a9ab27
+        return new Yaml(new SafeConstructor(), new Representer(), new DumperOptions(), new LoaderOptions(),
a9ab27
+                new Resolver());
a9ab27
     }
a9ab27
 
a9ab27
     private void reloadConfig() {
a9ab27
@@ -94,7 +108,7 @@ public class JmxCollector extends Collector implements Collector.Describable {
a9ab27
         FileReader fr = new FileReader(configFile);
a9ab27
 
a9ab27
         try {
a9ab27
-          Map<String, Object> newYamlConfig = (Map<String, Object>)new Yaml().load(fr);
a9ab27
+          Map<String, Object> newYamlConfig = (Map<String, Object>)createYamlInstance().load(fr);
a9ab27
           config = loadConfig(newYamlConfig);
a9ab27
           config.lastUpdate = configFile.lastModified();
a9ab27
           configReloadSuccess.inc();
a9ab27
diff --git a/collector/src/test/java/io/prometheus/jmx/JmxCollectorTest.java b/collector/src/test/java/io/prometheus/jmx/JmxCollectorTest.java
a9ab27
index 3d4ecf0..f499fb3 100644
a9ab27
--- a/collector/src/test/java/io/prometheus/jmx/JmxCollectorTest.java
a9ab27
+++ b/collector/src/test/java/io/prometheus/jmx/JmxCollectorTest.java
a9ab27
@@ -8,12 +8,15 @@ import static org.junit.Assert.fail;
a9ab27
 
a9ab27
 import java.io.File;
a9ab27
 import java.lang.management.ManagementFactory;
a9ab27
+import java.nio.file.Files;
a9ab27
+import java.util.stream.Collectors;
a9ab27
 
a9ab27
 import javax.management.MBeanServer;
a9ab27
 
a9ab27
 import org.junit.Before;
a9ab27
 import org.junit.BeforeClass;
a9ab27
 import org.junit.Test;
a9ab27
+import org.yaml.snakeyaml.constructor.ConstructorException;
a9ab27
 import org.yaml.snakeyaml.error.YAMLException;
a9ab27
 
a9ab27
 import io.prometheus.client.Collector;
a9ab27
@@ -272,4 +275,52 @@ public class JmxCollectorTest {
a9ab27
         assertEquals(prefix + "Number of aliases for non-scalar nodes exceeds the specified max=50", e.getMessage());
a9ab27
       }
a9ab27
     }
a9ab27
+
a9ab27
+	@Test
a9ab27
+	public void javaBeanLoadTestFile() throws Exception {
a9ab27
+	    try {
a9ab27
+	        File configFile = new File(getClass().getResource("/testyaml_javabean.config").getPath());
a9ab27
+	        doJavaBeanLoadTest(configFile, false);
a9ab27
+	    } finally {
a9ab27
+	        Person.fixtureReset();
a9ab27
+	    }
a9ab27
+	}
a9ab27
+
a9ab27
+	@Test
a9ab27
+    public void javaBeanLoadTestString() throws Exception {
a9ab27
+	    try {
a9ab27
+	        File configFile = new File(getClass().getResource("/testyaml_javabean.config").getPath());
a9ab27
+	        doJavaBeanLoadTest(configFile, true);
a9ab27
+	    } finally {
a9ab27
+	        Person.fixtureReset();
a9ab27
+	    }
a9ab27
+    }
a9ab27
+
a9ab27
+    private void doJavaBeanLoadTest(File configFile, boolean passAsString) throws Exception {
a9ab27
+        assertTrue(configFile.exists());
a9ab27
+        assertEquals(0, Person.loadCount.get());
a9ab27
+        try {
a9ab27
+            if (passAsString) {
a9ab27
+                String config = Files.readAllLines(configFile.toPath()).stream().collect(Collectors.joining("\n"));
a9ab27
+                new JmxCollector(config);
a9ab27
+            } else {
a9ab27
+                new JmxCollector(configFile);
a9ab27
+            }
a9ab27
+            assertEquals("Expected Person class to not be instantiated", 0, Person.loadCount.get());
a9ab27
+        } catch (ConstructorException e) {
a9ab27
+            String problem = e.getProblem();
a9ab27
+            assertTrue(problem.contains(Person.class.getName()));
a9ab27
+            assertTrue(problem.contains("could not determine a constructor"));
a9ab27
+        } catch (IllegalArgumentException e) {
a9ab27
+            Throwable cause = e.getCause();
a9ab27
+            if (cause instanceof ConstructorException) {
a9ab27
+                ConstructorException ce = (ConstructorException) cause;
a9ab27
+                String problem = ce.getProblem();
a9ab27
+                assertTrue(problem.contains(Person.class.getName()));
a9ab27
+                assertTrue(problem.contains("could not determine a constructor"));
a9ab27
+            } else {
a9ab27
+                fail("Expected ConstructorException as cause!");
a9ab27
+            }
a9ab27
+        }
a9ab27
+    }
a9ab27
 }
a9ab27
diff --git a/collector/src/test/java/io/prometheus/jmx/Person.java b/collector/src/test/java/io/prometheus/jmx/Person.java
a9ab27
new file mode 100644
a9ab27
index 0000000..e3b339a
a9ab27
--- /dev/null
a9ab27
+++ b/collector/src/test/java/io/prometheus/jmx/Person.java
a9ab27
@@ -0,0 +1,38 @@
a9ab27
+package io.prometheus.jmx;
a9ab27
+
a9ab27
+import java.util.concurrent.atomic.AtomicInteger;
a9ab27
+
a9ab27
+/**
a9ab27
+ * Simple java bean (used by yaml load test)
a9ab27
+ *
a9ab27
+ */
a9ab27
+public class Person {
a9ab27
+
a9ab27
+    public static final AtomicInteger loadCount = new AtomicInteger(0);
a9ab27
+
a9ab27
+    private String firstName;
a9ab27
+    private String lastName;
a9ab27
+
a9ab27
+    public String getFirstName() {
a9ab27
+        return firstName;
a9ab27
+    }
a9ab27
+
a9ab27
+    public void setFirstName(String firstName) {
a9ab27
+        loadCount.incrementAndGet();
a9ab27
+        this.firstName = firstName;
a9ab27
+    }
a9ab27
+
a9ab27
+    public String getLastName() {
a9ab27
+        return lastName;
a9ab27
+    }
a9ab27
+
a9ab27
+    public void setLastName(String lastName) {
a9ab27
+        loadCount.incrementAndGet();
a9ab27
+        this.lastName = lastName;
a9ab27
+    }
a9ab27
+
a9ab27
+    public static void fixtureReset() {
a9ab27
+        loadCount.set(0);
a9ab27
+    }
a9ab27
+
a9ab27
+}
a9ab27
diff --git a/collector/src/test/resources/testyaml_javabean.config b/collector/src/test/resources/testyaml_javabean.config
a9ab27
new file mode 100644
a9ab27
index 0000000..6552d83
a9ab27
--- /dev/null
a9ab27
+++ b/collector/src/test/resources/testyaml_javabean.config
a9ab27
@@ -0,0 +1,6 @@
a9ab27
+lowercaseOutputName: true
a9ab27
+lowercaseOutputLabelNames: true
a9ab27
+blacklistObjectNames:
a9ab27
+# handled by agent's default exporter
a9ab27
+- "java.lang:*"
a9ab27
+other: !!io.prometheus.jmx.Person { firstName: Andrey, lastName: Tool }
a9ab27
-- 
a9ab27
2.38.1
a9ab27