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)
signature.asc
Description: PGP signature
