[monitoring-plugins] check_{disk,load,ping,procs,swap}: OpenBSD ...

Alvar Penning git at monitoring-plugins.org
Sat Sep 12 12:20:14 CEST 2026


 Module: monitoring-plugins
 Branch: master
 Commit: 174bd9c00f34ae64fdb968b856a479ffa33d42ee
 Author: Alvar Penning <post at 0x21.biz>
   Date: Fri Sep 11 21:49:39 2026 +0200
    URL: https://www.monitoring-plugins.org/repositories/monitoring-plugins/commit/?id=174bd9c0

check_{disk,load,ping,procs,swap}: OpenBSD Hardening

Add OpenBSD hardening via pledge(2) and via unveil(2) for check plugins
executing other commands. Before an unveil(2) call is made, the command
path is extracted from the command defines, allowing only this command
to be executed.

---

 plugins/check_disk.c  |  5 +++++
 plugins/check_load.c  | 31 +++++++++++++++++++++++++++++++
 plugins/check_ping.c  | 30 ++++++++++++++++++++++++++++++
 plugins/check_procs.c | 29 +++++++++++++++++++++++++++++
 plugins/check_swap.c  | 14 ++++++++++++++
 5 files changed, 109 insertions(+)

diff --git a/plugins/check_disk.c b/plugins/check_disk.c
index e5104779..f254d848 100644
--- a/plugins/check_disk.c
+++ b/plugins/check_disk.c
@@ -115,6 +115,11 @@ const byte_unit PetaBytes_factor = 1000000000000000;
 const byte_unit ExaBytes_factor = 1000000000000000000;
 
 int main(int argc, char **argv) {
+#ifdef __OpenBSD__
+	/* - rpath is required to read --extra-opts and the partitions */
+	pledge("stdio rpath", NULL);
+#endif // __OpenBSD__
+
 	setlocale(LC_ALL, "");
 	bindtextdomain(PACKAGE, LOCALEDIR);
 	textdomain(PACKAGE);
diff --git a/plugins/check_load.c b/plugins/check_load.c
index a89c1577..62937461 100644
--- a/plugins/check_load.c
+++ b/plugins/check_load.c
@@ -117,6 +117,27 @@ static parsed_thresholds get_threshold(char *arg) {
 }
 
 int main(int argc, char **argv) {
+#ifdef __OpenBSD__
+	/* Restrict program execution to the ps binary. Continue allow reading all
+	 * files since arguments were not parsed at this point. */
+	char *ps_command, *ps_binary;
+	ps_command = malloc(strnlen(PS_COMMAND, BUFSIZ));
+
+	(void)strlcpy(ps_command, PS_COMMAND, strnlen(PS_COMMAND, BUFSIZ));
+	if (!(ps_binary = strtok(ps_command, " "))) {
+		die(STATE_UNKNOWN, "Cannot extract binary from %s", PS_COMMAND);
+	}
+	unveil(ps_binary, "rx");
+	free(ps_command);
+
+	unveil("/", "r");
+	unveil(NULL, NULL);
+
+	/* - rpath is required to read --extra-opts (given up later)
+	 * - proc and exec are used to fork and exec (given up later) */
+	pledge("stdio rpath proc exec", NULL);
+#endif // __OpenBSD__
+
 	setlocale(LC_ALL, "");
 	bindtextdomain(PACKAGE, LOCALEDIR);
 	textdomain(PACKAGE);
@@ -132,6 +153,12 @@ int main(int argc, char **argv) {
 
 	const check_load_config config = tmp_config.config;
 
+#ifdef __OpenBSD__
+	if (config.n_procs_to_show == 0) {
+		pledge("stdio", NULL);
+	}
+#endif // __OpenBSD__
+
 	double load_values[3] = {0, 0, 0};
 
 	// this should be getloadavg from gnulib, should work everywhere™
@@ -272,6 +299,10 @@ int main(int argc, char **argv) {
 		}
 
 		mp_add_subcheck_to_check(&overall, top_proc_sc);
+
+#ifdef __OpenBSD__
+		pledge("stdio", NULL);
+#endif // __OpenBSD__
 	}
 
 	mp_exit(overall);
diff --git a/plugins/check_ping.c b/plugins/check_ping.c
index 429cdaf3..02c36f26 100644
--- a/plugins/check_ping.c
+++ b/plugins/check_ping.c
@@ -68,6 +68,36 @@ static int verbose = 0;
 static char *warn_text;
 
 int main(int argc, char **argv) {
+#ifdef __OpenBSD__
+	/* Restrict program execution to the ping{,6} binaries. Continue allow
+	 * reading all files since arguments were not parsed at this point. */
+	char *ping_command, *ping_binary;
+	ping_command = malloc(strnlen(PING6_COMMAND, BUFSIZ));
+
+	(void)strlcpy(ping_command, PING_COMMAND, strnlen(PING_COMMAND, BUFSIZ));
+	if (!(ping_binary = strtok(ping_command, " "))) {
+		die(STATE_UNKNOWN, "Cannot extract binary from %s", PING_COMMAND);
+	}
+	unveil(ping_binary, "rx");
+
+	(void)strlcpy(ping_command, PING6_COMMAND, strnlen(PING6_COMMAND, BUFSIZ));
+	if (!(ping_binary = strtok(ping_command, " "))) {
+		die(STATE_UNKNOWN, "Cannot extract binary from %s", PING6_COMMAND);
+	}
+	unveil(ping_binary, "rx");
+
+	free(ping_command);
+
+	unveil("/", "r");
+	unveil(NULL, NULL);
+
+	/* - rpath is required to read --extra-opts
+	 * - dns for hostname resolution via mopl_net_is_host
+	 * - proc and exec are used to fork and exec
+	 * No promise is given up as they are all required within a loop. */
+	pledge("stdio rpath dns proc exec", NULL);
+#endif // __OpenBSD__
+
 	setlocale(LC_ALL, "");
 	setlocale(LC_NUMERIC, "C");
 	bindtextdomain(PACKAGE, LOCALEDIR);
diff --git a/plugins/check_procs.c b/plugins/check_procs.c
index 4f0c37e6..70ef0d5a 100644
--- a/plugins/check_procs.c
+++ b/plugins/check_procs.c
@@ -84,6 +84,10 @@ void print_usage(void);
 static int verbose = 0;
 
 static int stat_exe(const pid_t pid, struct stat *buf) {
+#ifdef __OpenBSD__
+	/* There is no procfs on OpenBSD. Use the "traditional" method instead. */
+	return -1;
+#endif // __OpenBSD__
 	char *path;
 	mopl_utils_xasprintf(&path, "/proc/%d/exe", pid);
 	int ret = stat(path, buf);
@@ -92,6 +96,27 @@ static int stat_exe(const pid_t pid, struct stat *buf) {
 }
 
 int main(int argc, char **argv) {
+#ifdef __OpenBSD__
+	/* Restrict program execution to the ps binary. Continue allow reading all
+	 * files since arguments were not parsed at this point. */
+	char *ps_command, *ps_binary;
+	ps_command = malloc(strnlen(PS_COMMAND, BUFSIZ));
+
+	(void)strlcpy(ps_command, PS_COMMAND, strnlen(PS_COMMAND, BUFSIZ));
+	if (!(ps_binary = strtok(ps_command, " "))) {
+		die(STATE_UNKNOWN, "Cannot extract binary from %s", PS_COMMAND);
+	}
+	unveil(ps_binary, "rx");
+	free(ps_command);
+
+	unveil("/", "r");
+	unveil(NULL, NULL);
+
+	/* - rpath is required to read --input-path, --extra-opts (given up later)
+	 * - proc and exec are used to fork and exec (given up later) */
+	pledge("stdio rpath proc exec", NULL);
+#endif // __OpenBSD__
+
 	setlocale(LC_ALL, "");
 	setlocale(LC_NUMERIC, "POSIX");
 	bindtextdomain(PACKAGE, LOCALEDIR);
@@ -145,6 +170,10 @@ int main(int argc, char **argv) {
 		result = cmd_file_read(config.input_filename, &chld_out, 0);
 	}
 
+#ifdef __OpenBSD__
+	pledge("stdio", NULL);
+#endif // __OpenBSD__
+
 	int pos; /* number of spaces before 'args' in `ps` output */
 	uid_t procuid = 0;
 	pid_t procpid = 0;
diff --git a/plugins/check_swap.c b/plugins/check_swap.c
index e3eb35c6..df48c324 100644
--- a/plugins/check_swap.c
+++ b/plugins/check_swap.c
@@ -68,6 +68,12 @@ const char *copyright = "2000-2024";
 const char *email = "devel at monitoring-plugins.org";
 
 int main(int argc, char **argv) {
+#ifdef __OpenBSD__
+	/* - rpath is required to read --extra-opts (given up later)
+	 * - vminfo is required for swapctl(2) (given up later) */
+	pledge("stdio rpath vminfo", NULL);
+#endif // __OpenBSD__
+
 	setlocale(LC_ALL, "");
 	bindtextdomain(PACKAGE, LOCALEDIR);
 	textdomain(PACKAGE);
@@ -81,6 +87,10 @@ int main(int argc, char **argv) {
 		mopl_utils_usage4(_("Could not parse arguments"));
 	}
 
+#ifdef __OpenBSD__
+	pledge("stdio vminfo", NULL);
+#endif // __OpenBSD__
+
 	swap_config config = tmp.config;
 
 	swap_result data = get_swap_data(config);
@@ -90,6 +100,10 @@ int main(int argc, char **argv) {
 		exit(STATE_UNKNOWN);
 	}
 
+#ifdef __OpenBSD__
+	pledge("stdio", NULL);
+#endif // __OpenBSD__
+
 	if (verbose) {
 		printf("Swap retrieval result:\n"
 			   "\tFree: %llu\n"



More information about the Commits mailing list