]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#4667] Fix null deref in getInterfacesKea
authorWlodek Wencel <wlodek@isc.org>
Thu, 23 Jul 2026 13:42:50 +0000 (15:42 +0200)
committerThomas Markwalder <tmark@isc.org>
Mon, 3 Aug 2026 19:00:18 +0000 (19:00 +0000)
Return early when interfaces-config is absent instead of
calling empty() on a null ElementPtr.

Closes #4667

Co-authored-by: Cursor <cursoragent@cursor.com>
changelog_unreleased/4667-getinterfaceskea-dereferences-null-elementptr-when-interfaces-config-is-absent [new file with mode: 0644]
src/lib/yang/tests/config_unittests.cc
src/lib/yang/translator_config.cc

diff --git a/changelog_unreleased/4667-getinterfaceskea-dereferences-null-elementptr-when-interfaces-config-is-absent b/changelog_unreleased/4667-getinterfaceskea-dereferences-null-elementptr-when-interfaces-config-is-absent
new file mode 100644 (file)
index 0000000..6600ec1
--- /dev/null
@@ -0,0 +1,5 @@
+[bug]          wlodek
+       Fixed a null ElementPtr dereference in
+       TranslatorConfig::getInterfacesKea when the YANG
+       config has no interfaces-config node.
+       (Gitlab #4667)
index 4e86d6af60e0b16d5729dd1e2089abee3d387be9..553bca4e7e3228a2ebcdf57df380b0c23cd41b78 100644 (file)
@@ -216,6 +216,32 @@ TEST_F(ConfigTestKeaV6, emptyKeaDhcp6) {
     EXPECT_TRUE(verify(emptyTreeKeaDhcp6));
 }
 
+// Regression: getConfig must not crash when interfaces-config is absent.
+TEST_F(ConfigTestKeaV4, getConfigWithoutInterfacesConfig) {
+    ASSERT_NO_THROW_LOG(load(subnetTwoPoolsJson4));
+    ConstElementPtr json;
+    ASSERT_NO_THROW_LOG(json = getJSON());
+    ASSERT_TRUE(json);
+    ConstElementPtr dhcp4 = json->get("Dhcp4");
+    ASSERT_TRUE(dhcp4);
+    EXPECT_FALSE(dhcp4->get("interfaces-config"));
+    ASSERT_TRUE(dhcp4->get("subnet4"));
+    EXPECT_EQ(1, dhcp4->get("subnet4")->size());
+}
+
+// Regression: getConfig must not crash when interfaces-config is absent.
+TEST_F(ConfigTestKeaV6, getConfigWithoutInterfacesConfig) {
+    ASSERT_NO_THROW_LOG(load(subnetTimersJson6));
+    ConstElementPtr json;
+    ASSERT_NO_THROW_LOG(json = getJSON());
+    ASSERT_TRUE(json);
+    ConstElementPtr dhcp6 = json->get("Dhcp6");
+    ASSERT_TRUE(dhcp6);
+    EXPECT_FALSE(dhcp6->get("interfaces-config"));
+    ASSERT_TRUE(dhcp6->get("subnet6"));
+    EXPECT_EQ(1, dhcp6->get("subnet6")->size());
+}
+
 // Check subnet with two pools with ietf-dhcpv6-server model.
 // Validation will fail because the current model has a vendor-info
 // container with a mandatory ent-num leaf and no presence flag,
index 25c2c952c4c982b139f824d4cbe0fd8e7ba28d0f..7e217ea4a8b1169e85307521bf3ea49f4eaa47fe 100644 (file)
@@ -157,22 +157,24 @@ TranslatorConfig::getConfigControlKea(DataNode const& data_node) {
 
 ElementPtr
 TranslatorConfig::getInterfacesKea(DataNode const& config) {
-    ElementPtr result;
     optional<DataNode> const& interfaces_config_optional(config.findPath("interfaces-config"));
-    if (interfaces_config_optional) {
-        DataNode const interfaces_config(*interfaces_config_optional);
-        result = Element::createMap();
+    if (!interfaces_config_optional) {
+        return (ElementPtr());
+    }
 
-        checkAndGetLeaf(result, interfaces_config, "dhcp-socket-type");
-        checkAndGetLeaf(result, interfaces_config, "interfaces");
-        checkAndGetLeaf(result, interfaces_config, "outbound-interface");
-        checkAndGetLeaf(result, interfaces_config, "re-detect");
-        checkAndGetLeaf(result, interfaces_config, "service-sockets-max-retries");
-        checkAndGetLeaf(result, interfaces_config, "service-sockets-require-all");
-        checkAndGetLeaf(result, interfaces_config, "service-sockets-retry-wait-time");
+    DataNode const interfaces_config(*interfaces_config_optional);
+    ElementPtr result = Element::createMap();
+
+    checkAndGetLeaf(result, interfaces_config, "dhcp-socket-type");
+    checkAndGetLeaf(result, interfaces_config, "interfaces");
+    checkAndGetLeaf(result, interfaces_config, "outbound-interface");
+    checkAndGetLeaf(result, interfaces_config, "re-detect");
+    checkAndGetLeaf(result, interfaces_config, "service-sockets-max-retries");
+    checkAndGetLeaf(result, interfaces_config, "service-sockets-require-all");
+    checkAndGetLeaf(result, interfaces_config, "service-sockets-retry-wait-time");
+
+    checkAndGetAndJsonifyLeaf(result, interfaces_config, "user-context");
 
-        checkAndGetAndJsonifyLeaf(result, interfaces_config, "user-context");
-    }
     return (result->empty() ? ElementPtr() : result);
 }