On Wed Jul 22, 2026 at 10:57 AM EDT, Stuart Henderson wrote:
> the revised pledge still feels like shoehorning it into a program
> which has not been designed to actually work with it. big clue
> is having file access and network access in the same process.
> (sure, there's worse in ports, and it's not a total blocker, but
> it does make me wonder how well tested it's been, because clearly
> there hasn't been too much careful thought about how to use this
> prior to it being committed uptream..)

I've replaced upstream's pledge/unveil with what I had been drafting but
never finished a few months ago. Looking for feedback before I submit it
to upstream.  Unfortunately i2pd doesn't have a test suite as far as I
can tell so I find it difficult to make sure all bases have been covered
across pledge/unveil. I ran it for a few minutes and saw no EPERM.

Doesn't resolve the issue of simul net/file access but I think this
design actually has some thought put into it :p

Andrew


commit f2d7f170ad404eec631c71cda706ad79e252af2c
Author: Andrew Kloet <[email protected]>
Date:   Wed Jul 22 08:40:12 2026 -0400

    daemon: redo pledge/unveil

diff --git a/daemon/Daemon.cpp b/daemon/Daemon.cpp
index ecb73965..022b59f2 100644
--- a/daemon/Daemon.cpp
+++ b/daemon/Daemon.cpp
@@ -10,10 +10,6 @@
 #include <memory>
 #include <regex>

-#ifdef __OpenBSD__
-#      include<unistd.h>
-#endif
-
 #include "Daemon.h"

 #include "Config.h"
@@ -107,84 +103,6 @@ namespace util
                i2p::config::ParseConfig(config);
                i2p::config::Finalize();

-#ifdef __OpenBSD__
-               auto init_pledge = []() {
-                       std::string pledge_file; 
i2p::config::GetOption("openbsd.pledge_file", pledge_file);
-                       if (pledge_file == "")
-                       {
-                               LogPrint(eLogDebug, "Use default pledge 
values");
-                               // TODO: remove that not need
-                               pledge("stdio rpath wpath cpath inet dns unix 
recvfd sendfd proc error mcast chown flock",nullptr);
-                       } else {
-                               std::ifstream f(pledge_file);
-                               if(!f) {
-                                       std::cerr << "Can't open pledge file " 
<< pledge_file<<std::endl;
-                                       exit(1);
-                               }
-                               std::string line;
-                               std::vector<std::string> rules;
-                               while(std::getline(f, line)){
-                                       rules.push_back(line);
-                               }
-                               if(f.bad()) {
-                                       std::cerr << "IO error with pledge 
file" << std::endl;
-                               }
-                               std::ostringstream out;
-                               for(auto r : rules)
-                                       out << r << " ";
-                               pledge(out.str().c_str(), nullptr);
-                       }
-
-
-               };
-               auto init_unevil = []() {
-                       unveil("/usr/lib", "r");
-                       unveil("/usr/local/lib", "r");
-                       unveil("/usr/libexec/ld.so", "r");
-                       unveil("/dev/urandom", "r");
-                       unveil("/tmp", "rw");
-                       unveil("/etc/i2pd", "r"); // ваще не нужно вроде на 
весь прям каталог
-
-                       #define UNVEIL_DIR(dir) unveil(dir.c_str(), "rwc")
-
-                       std::string unevil_file; 
i2p::config::GetOption("openbsd.unevil_file",unevil_file);
-                       UNVEIL_DIR(unevil_file);
-                       std::string tunnelsdir, certsdir, logfile, datadir, 
reseed_file, openbsd_pledge_file;
-                       i2p::config::GetOption("tunnelsdir", tunnelsdir);
-                       UNVEIL_DIR(tunnelsdir);
-                       i2p::config::GetOption("certsdir", certsdir);
-                       UNVEIL_DIR(certsdir);
-                       i2p::config::GetOption("datadir", datadir);
-                       UNVEIL_DIR(datadir);
-                       i2p::config::GetOption("reseed.file", reseed_file);
-                       unveil(reseed_file.c_str(), "r");
-                       i2p::config::GetOption("openbsd.pledge_file", 
openbsd_pledge_file);
-                       unveil(openbsd_pledge_file.c_str(), "r");
-                       std::string tunconf ;i2p::config::GetOption("tunconf", 
tunconf); unveil(tunconf.c_str(), "r");
-                       std::string conf ;i2p::config::GetOption("tunconf", 
conf); unveil(conf.c_str(), "r");
-                       std::string pidfile ;i2p::config::GetOption("pidfile", 
pidfile); unveil(pidfile.c_str(), "rwc");
-                       i2p::config::GetOption("logfile", logfile); 
unveil(logfile.c_str(), "rwc");
-                       if(unevil_file != "")
-                       {
-                               std::ifstream f(unevil_file);
-                               if (!f) {
-                                       std::cerr << "Can't open unevil file" 
<< std::endl;
-                                       exit(1);
-                               }
-                               std::string line;
-                               while(std::getline(f, line)){
-                                               UNVEIL_DIR(line);
-                               }
-                       }
-                       #undef UNVEIL_DIR
-                       unveil(NULL, NULL);
-               };
-               bool openbsd_unevil_enabled; 
i2p::config::GetOption("openbsd.unevil_enabled", openbsd_unevil_enabled);
-               bool openbsd_pledge_enabled; 
i2p::config::GetOption("openbsd.pledge_enabled", openbsd_pledge_enabled);
-               if(openbsd_unevil_enabled) init_unevil();
-               if(openbsd_pledge_enabled) init_pledge();
-#endif
-
                i2p::config::GetOption("daemon", isDaemon);

                std::string certsdir; i2p::config::GetOption("certsdir", 
certsdir);
diff --git a/daemon/UnixDaemon.cpp b/daemon/UnixDaemon.cpp
index 43c3c9de..e74bb57b 100644
--- a/daemon/UnixDaemon.cpp
+++ b/daemon/UnixDaemon.cpp
@@ -210,6 +210,44 @@ namespace i2p
                                sigaction(SIGCONT, &sa, 0);
                        }

+#ifdef __OpenBSD__
+                       std::string dataDir = i2p::fs::GetDataDir();
+                       if (!dataDir.empty())
+                               if (unveil(dataDir.c_str(), "rwc") == -1)
+                                       LogPrint(eLogError, "Daemon: Unveil 
failed for dataDir (", dataDir, "): ", std::strerror(errno));
+
+                       auto unveilConfigOption = [](const std::string& key, 
const char* mask) {
+                               std::string path;
+                               if (i2p::config::GetOption(key, path) && 
!path.empty())
+                                       if (unveil(path.c_str(), mask) == -1)
+                                               LogPrint(eLogError, "Daemon: 
Unveil failed for ", key, " (", path, "): ", std::strerror(errno));
+                       };
+
+                       const std::vector<std::pair<std::string, const char*>> 
unveilRules = {
+                               {"conf",           "r"},
+                               {"certsdir",       "r"},
+                               {"tunconf",        "r"},
+                               {"tunnelsdir",     "r"},
+                               {"pidfile",        "rwc"},
+                               {"logfile",        "rwc"},
+                               {"reseed.file",    "r"},
+                               {"reseed.zipfile", "r"}
+                       };
+
+                       for (const auto& rule : unveilRules)
+                               unveilConfigOption(rule.first, rule.second);
+
+                       if (unveil(NULL, NULL) == -1) {
+                               LogPrint(eLogError, "Daemon: unveil lock 
failed: ", std::strerror(errno));
+                               exit(1);
+                       }
+
+                       if (pledge("stdio inet dns flock rpath wpath cpath 
proc", NULL) == -1) {
+                               LogPrint(eLogError, "Daemon: pledge failed: ", 
std::strerror(errno));
+                               exit(1);
+                       }
+#endif
+
                        return Daemon_Singleton::start();
                }

diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp
index fe406b13..ea137597 100644
--- a/libi2pd/Config.cpp
+++ b/libi2pd/Config.cpp
@@ -396,16 +396,6 @@ namespace config {
                ;
 #endif

-#ifdef __OpenBSD__
-               options_description openbsd_specific("OpenBSD specific 
options");
-               openbsd_specific.add_options()
-                       ("openbsd.pledge_file", 
value<std::string>()->default_value(""), "OpenbSD file with pledge rules")
-                       ("openbsd.unevil_file", 
value<std::string>()->default_value(""), "OpenBSD file with unevil rules")
-                       ("openbsd.unevil_enabled", 
value<bool>()->default_value(true),     "use unevil rues")
-                       ("openbsd.pledge_enabled", 
value<bool>()->default_value(true),     "use pledge rules")
-                       ;
-#endif
-
                m_OptionsDesc
                        .add(general)
                        .add(limits)

Attachment: signature.asc
Description: PGP signature

Reply via email to