[PATCH 1/5] neuter /help iff in restricted mode

[PATCH 1/5] neuter /help iff in restricted mode

From: Klemens Nanni
This goes in line with not executing progams and is in fact required on
OpenBSD to prevent catgirl from ever executing anything without doing
harm (see following commits).
---
 command.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/command.c b/command.c
index 998d9a2..501bff4 100644
--- a/command.c
+++ b/command.c
@@ -458,6 +458,11 @@ static void commandHelp(uint id, char *params) {
 		return;
 	}
 
+	if (self.restricted) {
+		uiFormat(id, Warm, NULL, "see catgirl(1)", NULL);
+		return;
+	}
+
 	uiHide();
 	pid_t pid = fork();
 	if (pid < 0) err(EX_OSERR, "fork");
-- 
2.30.0

1 reply

[PATCH 2/5] openbsd: pledge after unveil, always

From: Klemens Nanni
sandbox() does not finalize unveil(2) by calling unveil(NULL, NULL),
i.e. further calls would be allowed during runtime.

Simply logic, be more idiomatic and finalize by pledging after all
unveiling is done by omitting the "unveil" promise and thereby not
allowing further calls to it.
---
 chat.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/chat.c b/chat.c
index ebffe46..78b6ab7 100644
--- a/chat.c
+++ b/chat.c
@@ -142,11 +142,7 @@ static void unveilData(const char *name) {
 	}
 }
 
-static void sandbox(const char *trust, const char *cert, const char *priv) {
-	int error = pledge(
-		"stdio rpath wpath cpath inet dns tty proc exec unveil", NULL
-	);
-	if (error) err(EX_OSERR, "pledge");
+static void unveilAll(const char *trust, const char *cert, const char *priv) {
 	if (!self.restricted) return;
 
 	dataMkdir("");
@@ -284,7 +280,9 @@ int main(int argc, char *argv[]) {
 	commandCompleteAdd();
 
 #ifdef __OpenBSD__
-	sandbox(trust, cert, priv);
+	unveilAll(trust, cert, priv);
+	if (pledge("stdio rpath wpath cpath inet dns tty proc exec", NULL) == -1)
+		err(EX_OSERR, "pledge");
 #endif
 
 	ircConfig(insecure, trust, cert, priv);
-- 
2.30.0

1 reply

[PATCH 3/5] openbsd: Drop network capability after ircConnect()

From: Klemens Nanni
catgirl has no reconnect feature and generally must not do
anything but read/write from/to the connected socket which
does not require "inet" or "dns" promises.
---
 chat.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/chat.c b/chat.c
index 78b6ab7..210ea8a 100644
--- a/chat.c
+++ b/chat.c
@@ -309,6 +309,10 @@ int main(int argc, char *argv[]) {
 	uiDraw();
 	
 	int irc = ircConnect(bind, host, port);
+#ifdef __OpenBSD__
+	if (pledge("stdio rpath wpath cpath tty proc exec", NULL) == -1)
+		err(EX_OSERR, "pledge");
+#endif
 	if (pass) ircFormat("PASS :%s\r\n", pass);
 	if (sasl) ircFormat("CAP REQ :sasl\r\n");
 	ircFormat("CAP LS\r\n");
-- 
2.30.0

1 reply

[PATCH 4/5] openbsd: drop exec capability iff restricted

From: Klemens Nanni
Nothing must be executed when running /opy, et al.
---
 chat.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/chat.c b/chat.c
index 210ea8a..02d225b 100644
--- a/chat.c
+++ b/chat.c
@@ -340,6 +340,13 @@ int main(int argc, char *argv[]) {
 		fcntl(execPipe[1], F_SETFD, FD_CLOEXEC);
 	}
 
+#ifdef __OpenBSD__
+	if (self.restricted) {
+		if (pledge("stdio rpath wpath cpath tty", NULL) == -1)
+			err(EX_OSERR, "pledge");
+	}
+#endif
+
 	struct pollfd fds[] = {
 		{ .events = POLLIN, .fd = STDIN_FILENO },
 		{ .events = POLLIN, .fd = irc },
-- 
2.30.0

2 replies

[PATCH 5/5] openbsd: drop filesystem access iff possible

From: Klemens Nanni
Log files and state save/restore both require read/write access to
the filesystem, both during start and exit.

If neither features are used, catgirl may run with "stdio tty".
---
 chat.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/chat.c b/chat.c
index 02d225b..3d91d80 100644
--- a/chat.c
+++ b/chat.c
@@ -341,10 +341,13 @@ int main(int argc, char *argv[]) {
 	}
 
 #ifdef __OpenBSD__
-	if (self.restricted) {
-		if (pledge("stdio rpath wpath cpath tty", NULL) == -1)
-			err(EX_OSERR, "pledge");
-	}
+	char final_promises[64] = "stdio tty";
+	if (save || logEnable)
+		strlcat(final_promises, " rpath wpath cpath", sizeof(final_promises));
+	if (!self.restricted)
+		strlcat(final_promises, " proc exec", sizeof(final_promises));
+	if (pledge(final_promises, NULL) == -1)
+		err(EX_OSERR, "pledge");
 #endif
 
 	struct pollfd fds[] = {
-- 
2.30.0