]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#3842] backport #3832 to 2_6
authorRazvan Becheriu <razvan@isc.org>
Wed, 7 May 2025 11:38:22 +0000 (14:38 +0300)
committerRazvan Becheriu <razvan@isc.org>
Tue, 13 May 2025 14:59:46 +0000 (17:59 +0300)
13 files changed:
ChangeLog
src/bin/admin/kea-admin.in
src/bin/agent/main.cc
src/bin/d2/main.cc
src/bin/dhcp4/main.cc
src/bin/dhcp6/main.cc
src/bin/keactrl/keactrl.in
src/bin/lfc/main.cc
src/bin/netconf/main.cc
src/bin/perfdhcp/main.cc
src/lib/util/filesystem.cc
src/lib/util/filesystem.h
src/lib/util/tests/filesystem_unittests.cc

index 77f8b4e824f53e0c85c0abcfd973814292cb5505..a69128a99b48140a31c16ea7c3de6b7ddd152fb3 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2265.  [sec]*          fdupont
+       Change the umask to no group write and no other access
+       at the entry of Kea server/agent binaries.
+       CVE:2025-32803
+       (Gitlab #3842, #3832)
+
 2264.  [sec]*          tmark
        kea-dhcp4, kea-dhcp6, kea-dhcp-ddns, and kea-ctrl-agent will
        now only load hook libraries from the default installation
@@ -20,7 +26,6 @@
        removed as of libc++ 19.
        (Gitlab #3823, #3532)
 
-
 Kea 2.6.2 (stable) released on March 26, 2025
 
 2261.  [build]         mgodzina
index c87acb993e190f3f8e8e97ac5e090936d9f804ad..979735949634d783280a4618bdcb54ba3e14ad55 100644 (file)
 # used.
 set -eu
 
+# Set no group write and no other access umask
+orig_umask=$(umask)
+umask $((orig_umask | 0027))
+
 # Shell ${variables} derived from autoconf @variables@. Some depend on others, so mind the order.
 prefix="@prefix@"
 export prefix
index 68687083a6775366e1675c7c5eb22a25c5ac2058..0d3b3c6b77f3b9ad5944e3a56cfbe885cede236c 100644 (file)
@@ -7,6 +7,7 @@
 #include <config.h>
 #include <agent/ca_controller.h>
 #include <exceptions/exceptions.h>
+#include <util/filesystem.h>
 #include <cstdlib>
 #include <iostream>
 
@@ -14,6 +15,8 @@ using namespace isc::agent;
 using namespace isc::process;
 
 int main(int argc, char* argv[]) {
+    isc::util::file::setUmask();
+
     int ret = EXIT_SUCCESS;
 
     // Launch the controller passing in command line arguments.
index 25975a77d39ed6a864591c1f46f37758144d0535..7a06993e2002143b303375845200c1f7dd490cd6 100644 (file)
@@ -10,6 +10,7 @@
 #include <exceptions/exceptions.h>
 #include <log/logger_manager.h>
 #include <log/logger_support.h>
+#include <util/filesystem.h>
 
 #include <iostream>
 
@@ -23,6 +24,8 @@ using namespace std;
 /// The exit value of the program will be EXIT_SUCCESS if there were no
 /// errors, EXIT_FAILURE otherwise.
 int main(int argc, char* argv[]) {
+    isc::util::file::setUmask();
+
     int ret = EXIT_SUCCESS;
 
     // Launch the controller passing in command line arguments.
index 7979a0466642a0dc407c21b64659e50ee8540e96..7b61a67078e244601277fc18bcbe6e57aa1fd251 100644 (file)
@@ -18,6 +18,7 @@
 #include <log/output_option.h>
 #include <process/cfgrpt/config_report.h>
 #include <process/daemon.h>
+#include <util/filesystem.h>
 
 #include <boost/lexical_cast.hpp>
 
@@ -71,6 +72,8 @@ usage() {
 
 int
 main(int argc, char* argv[]) {
+    isc::util::file::setUmask();
+
     int ch;
     // The default. Any other values are useful for testing only.
     int server_port_number = DHCP4_SERVER_PORT;
index fcfff7df53508669f7f3a87d1d5d0ab8e1106116..6d08711f109c2cef6ea494b512c3acc5acd61ecf 100644 (file)
@@ -18,6 +18,7 @@
 #include <log/output_option.h>
 #include <process/cfgrpt/config_report.h>
 #include <process/daemon.h>
+#include <util/filesystem.h>
 
 #include <boost/lexical_cast.hpp>
 
@@ -71,6 +72,8 @@ usage() {
 
 int
 main(int argc, char* argv[]) {
+    isc::util::file::setUmask();
+
     int ch;
     // The default. Any other values are useful for testing only.
     int server_port_number = DHCP6_SERVER_PORT;
index cccfdac303156e5957a0f3ac0c94aae79576edf5..50770912468fd1c00d92e1c954a61e113bd68ce1 100644 (file)
 # used.
 set -eu
 
+# Set no group write and no other access umask
+orig_umask=$(umask)
+umask $((orig_umask | 0027))
+
 PACKAGE_VERSION="@PACKAGE_VERSION@"
 EXTENDED_VERSION="@EXTENDED_VERSION@"
 
index 1b49e9625a8c537d9ad2dee4d52657bb00a45177..6b9430a67b77f4234013103f07c110e494bac02f 100644 (file)
@@ -9,6 +9,7 @@
 #include <exceptions/exceptions.h>
 #include <log/logger_support.h>
 #include <log/logger_manager.h>
+#include <util/filesystem.h>
 #include <boost/exception/diagnostic_information.hpp>
 #include <boost/exception_ptr.hpp>
 #include <iostream>
@@ -24,6 +25,8 @@ using namespace isc::lfc;
 /// The exit value of the program will be EXIT_SUCCESS if there were no
 /// errors, EXIT_FAILURE otherwise.
 int main(int argc, char* argv[]) {
+    isc::util::file::setUmask();
+
     int ret = EXIT_SUCCESS;
     try {
         // Ask scheduling to not give too much resources to LFC.
index a6ac2a14af436d54c83b053bde8fa227613644d3..bc241ea51e102e6530b7bddc6c45ec424196cd82 100644 (file)
@@ -7,6 +7,7 @@
 #include <config.h>
 
 #include <exceptions/exceptions.h>
+#include <util/filesystem.h>
 #include <netconf/netconf_controller.h>
 
 #include <cstdlib>
@@ -18,6 +19,8 @@ using namespace isc::process;
 using namespace std;
 
 int main(int argc, char* argv[]) {
+    isc::util::file::setUmask();
+
     int ret = EXIT_SUCCESS;
 
     // Launch the controller passing in command line arguments.
index 5262ace5fac4ad62c681cfa328e5f08d23cf1549..1572d8d79f89ef9b63994075cc06c6ff35d0126f 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <config.h>
 
+#include <util/filesystem.h>
 #include <perfdhcp/avalanche_scen.h>
 #include <perfdhcp/basic_scen.h>
 #include <perfdhcp/command_options.h>
@@ -19,6 +20,8 @@ using namespace isc::perfdhcp;
 
 int
 main(int argc, char* argv[]) {
+    isc::util::file::setUmask();
+
     int ret_code = 0;
     std::string diags;
     bool parser_error = true;
index 46946a228c6f6bf79a04d283d60441002bd80f5a..f807db18e1e491de5a22a5443e4e40c8657441e5 100644 (file)
@@ -69,21 +69,15 @@ isFile(string const& path) {
     return ((statbuf.st_mode & S_IFMT) == S_IFREG);
 }
 
-Umask::Umask(mode_t mask) : orig_umask_(umask(S_IWGRP | S_IWOTH)) {
-    umask(orig_umask_ | mask);
-}
-
-Umask::~Umask() {
-    umask(orig_umask_);
-}
-
-bool
-isSocket(string const& path) {
-    struct stat statbuf;
-    if (::stat(path.c_str(), &statbuf) < 0) {
-        return (false);
+void
+setUmask() {
+    // No group write and no other access.
+    mode_t mask(S_IWGRP | S_IRWXO);
+    mode_t orig = umask(mask);
+    // Handle the case where the original umask was already more restrictive.
+    if ((orig | mask) != mask) {
+        static_cast<void>(umask(orig | mask));
     }
-    return ((statbuf.st_mode & S_IFMT) == S_IFSOCK);
 }
 
 Path::Path(string const& full_name) {
index d726c3178cc6dff72eeed462abb30ca4986ddd40..34e7aad24b5605e10f2b4c59897bc6cdbf1fcf7d 100644 (file)
@@ -49,27 +49,11 @@ isDir(const std::string& path);
 bool
 isFile(const std::string& path);
 
-/// @brief RAII device to limit access of created files.
-struct Umask {
-    /// @brief Constructor
-    ///
-    /// Set wanted bits in umask.
-    Umask(mode_t mask);
-
-    /// @brief Destructor.
-    ///
-    /// Restore umask.
-    ~Umask();
-
-private:
-    /// @brief Original umask.
-    mode_t orig_umask_;
-};
-
-bool
-isSocket(const std::string& path);
+/// @brief Set umask (at least 0027 i.e. no group write and no other access).
+void
+setUmask();
 
-/// @brief Paths on a filesystem
+/// \brief Paths on a filesystem
 struct Path {
     /// @brief Constructor
     ///
index 1b6e792a153a425b3bccf6facb32bed460c8f6b3..bd309ca19525e7bae111402d008e9b3afe9a8d4a 100644 (file)
@@ -70,16 +70,37 @@ TEST_F(FileUtilTest, isFile) {
     EXPECT_FALSE(isFile(TEST_DATA_BUILDDIR));
 }
 
-/// @brief Check Umask.
-TEST_F(FileUtilTest, umask) {
-    // Protect the test itself assuming that Umask does what we expect...
-    Umask m0(0);
-    mode_t orig = umask(0);
-    {
-        Umask m(S_IROTH);
-        EXPECT_EQ(S_IROTH, umask(S_IRWXO));
+/// @brief Test fixture class for testing operations on umask.
+struct UMaskUtilTest : ::testing::Test {
+    /// @brief Constructor.
+    ///
+    /// Cache the original umask value.
+    UMaskUtilTest() : orig_umask_(umask(S_IWGRP | S_IWOTH)) { }
+
+    /// @brief Destructor.
+    ///
+    /// Restore the original umask value.
+    virtual ~UMaskUtilTest() {
+        static_cast<void>(umask(orig_umask_));
     }
-    EXPECT_EQ(0, umask(orig));
+
+private:
+    /// @brief Original umask.
+    mode_t orig_umask_;
+};
+
+/// @brief Check setUmask from 0000.
+TEST_F(UMaskUtilTest, umask0) {
+    static_cast<void>(umask(0));
+    ASSERT_NO_THROW(setUmask());
+    EXPECT_EQ(S_IWGRP | S_IRWXO, umask(0));
+}
+
+/// @brief Check setUmask from no group access.
+TEST_F(UMaskUtilTest, umask077) {
+    static_cast<void>(umask(S_IRWXG | S_IRWXO));
+    ASSERT_NO_THROW(setUmask());
+    EXPECT_EQ(S_IRWXG | S_IRWXO, umask(0));
 }
 
 /// @brief Check that the components are split correctly.