Commit Diff


commit - 1f480907e29bc783454427371277ef33a25658e4
commit + 97799ccd4b67a81f97039305d4fdd66588da9962
blob - 958a3d67dfe92ddf1caf9fd8e3586f887a36001b
blob + 0b90a45a21dee8de83282118e67277aef5bd3370
--- compat/Makefile.am
+++ compat/Makefile.am
@@ -31,6 +31,10 @@ else
 libopenbsd_compat_a_SOURCES += uuid.c
 endif
 
+if HAVE_LINUX_LANDLOCK
+libopenbsd_compat_a_SOURCES += landlock.c
+endif
+
 EXTRA_DIST = \
 	$(top_srcdir)/include/got_compat.h \
 	imsg.h \
blob - /dev/null
blob + 47a5209dbfe20f149a142f16faaca86ca659120c (mode 644)
--- /dev/null
+++ compat/landlock.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2021 Omar Polo <op@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/landlock.h>
+#include <linux/prctl.h>
+
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <limits.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "got_compat.h"
+
+/*
+ * What's the deal with landlock?  While distro with linux >= 5.13
+ * have the struct declarations, libc wrappers are missing.  The
+ * sample landlock code provided by the authors includes these "shims"
+ * in their example for the landlock API until libc provides them.
+ */
+
+#ifndef landlock_create_ruleset
+static inline int
+landlock_create_ruleset(const struct landlock_ruleset_attr *attr, size_t size,
+    __u32 flags)
+{
+	return syscall(__NR_landlock_create_ruleset, attr, size, flags);
+}
+#endif
+
+#ifndef landlock_add_rule
+static inline int
+landlock_add_rule(int ruleset_fd, enum landlock_rule_type type,
+    const void *attr, __u32 flags)
+{
+	return syscall(__NR_landlock_add_rule, ruleset_fd, type, attr, flags);
+}
+#endif
+
+#ifndef landlock_restrict_self
+static inline int
+landlock_restrict_self(int ruleset_fd, __u32 flags)
+{
+	return syscall(__NR_landlock_restrict_self, ruleset_fd, flags);
+}
+#endif
+
+/*
+ * Revoke any fs access.
+ */
+int
+landlock_no_fs(void)
+{
+	struct landlock_ruleset_attr rattr = {
+		/*
+		 * handled_access_fs can't be zero!  Even if we don't
+		 * add any path at all with landlock_add_rule, and thus
+		 * rejecting *any* filesystem access, we still have to
+		 * list some "possible actions" here.
+		 */
+		.handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE,
+	};
+	int fd, saved_errno;
+
+	if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1)
+		return -1;
+
+	fd = landlock_create_ruleset(&rattr, sizeof(rattr), 0);
+	if (fd == -1) {
+		/* this kernel doesn't have landlock built in */
+		if (errno == ENOSYS || errno == ENOTSUP)
+			return 0;
+		return -1;
+	}
+
+	if (landlock_restrict_self(fd, 0)) {
+		saved_errno = errno;
+		close(fd);
+		errno = saved_errno;
+		return -1;
+	}
+
+	close(fd);
+	return 0;
+}
blob - a9b188be681d73c01d831cd71a266058697cd6ab
blob + 44604f740f93329e013205265626d19b5450fe04
--- configure.ac
+++ configure.ac
@@ -42,6 +42,7 @@ AC_CHECK_HEADERS([ \
 	fcntl.h \
 	langinfo.h \
 	limits.h \
+	linux/landlock.h \
 	locale.h \
 	netdb.h \
 	netinet/in.h \
@@ -163,6 +164,16 @@ AC_SUBST(PLATFORM)
 AM_CONDITIONAL([HOST_FREEBSD], [test "$PLATFORM" = "freebsd"])
 AM_CONDITIONAL([HOST_LINUX], [test "$PLATFORM" = "linux"])
 
+# Landlock detection.
+AC_MSG_CHECKING([for landlock])
+AM_CONDITIONAL([HAVE_LINUX_LANDLOCK],
+    [test "x$ac_cv_header_linux_landlock_h" = "xyes"])
+if test "x$ac_cv_header_linux_landlock_h" = "xyes"; then
+	AC_MSG_RESULT(yes)
+else
+	AC_MSG_RESULT(no)
+fi
+
 # Clang sanitizers wrap reallocarray even if it isn't available on the target
 # system. When compiled it always returns NULL and crashes the program. To
 # detect this we need a more complicated test.
blob - c07416a808a6799841c0c9978d004659680beda2
blob + 43e2e48d8e287757aa51bd8b89fa4d136904b88d
--- include/got_compat.h
+++ include/got_compat.h
@@ -41,6 +41,12 @@
 #ifndef __OpenBSD__
 #define pledge(s, p) (0)
 #define unveil(s, p) (0)
+#endif
+
+#ifndef HAVE_LINUX_LANDLOCK_H
+#define landlock_no_fs() (0)
+#else
+int	landlock_no_fs(void);
 #endif
 
 #ifndef INFTIM
blob - 65c075409a0f6850f37b585385b6429b80a143ed
blob + 5d5fc4944fb66148926a3e2aa218adf907063461
--- libexec/got-fetch-pack/got-fetch-pack.c
+++ libexec/got-fetch-pack/got-fetch-pack.c
@@ -809,6 +809,13 @@ main(int argc, char **argv)
 		got_privsep_send_error(&ibuf, err);
 		return 1;
 	}
+
+	/* revoke fs access */
+	if (landlock_no_fs() == -1) {
+		err = got_error_from_errno("landlock_no_fs");
+		got_privsep_send_error(&ibuf, err);
+		return 1;
+	}
 #endif
 	err = got_privsep_recv_imsg(&imsg, &ibuf, 0);
 	if (err) {
blob - b8572cfe5b35acf5d04456dc811ef5e1cf3b918d
blob + bfaf074f9691171d53deb75a04179c2f13c5fbc3
--- libexec/got-index-pack/got-index-pack.c
+++ libexec/got-index-pack/got-index-pack.c
@@ -1008,6 +1008,13 @@ main(int argc, char **argv)
 		got_privsep_send_error(&ibuf, err);
 		return 1;
 	}
+
+	/* revoke fs access */
+	if (landlock_no_fs() == -1) {
+		err = got_error_from_errno("landlock_no_fs");
+		got_privsep_send_error(&ibuf, err);
+		return 1;
+	}
 #endif
 	err = got_privsep_recv_imsg(&imsg, &ibuf, 0);
 	if (err)
blob - 24a9911b4e2319200c86e0be0d525a3980763d80
blob + cea6f43adac14aa61fc01c67ea2223fe2ec4b367
--- libexec/got-read-blob/got-read-blob.c
+++ libexec/got-read-blob/got-read-blob.c
@@ -65,6 +65,13 @@ main(int argc, char *argv[])
 		got_privsep_send_error(&ibuf, err);
 		return 1;
 	}
+
+	/* revoke fs access */
+	if (landlock_no_fs() == -1) {
+		err = got_error_from_errno("landlock_no_fs");
+		got_privsep_send_error(&ibuf, err);
+		return 1;
+	}
 #endif
 
 	for (;;) {
blob - f324bf809bdb1dbc68030ee2676b88f4ec11dc4e
blob + 75b69cf033167c2237a8a02aeebd0f48a8d649ea
--- libexec/got-read-commit/got-read-commit.c
+++ libexec/got-read-commit/got-read-commit.c
@@ -119,6 +119,13 @@ main(int argc, char *argv[])
 		got_privsep_send_error(&ibuf, err);
 		return 1;
 	}
+
+	/* revoke fs access */
+	if (landlock_no_fs() == -1) {
+		err = got_error_from_errno("landlock_no_fs");
+		got_privsep_send_error(&ibuf, err);
+		return 1;
+	}
 #endif
 
 	for (;;) {
blob - 9820c8bd9e58d215598df363fdb6e25fbd81323d
blob + 1ccc67e3c4467f8056bf23a367d62431de5219bd
--- libexec/got-read-gitconfig/got-read-gitconfig.c
+++ libexec/got-read-gitconfig/got-read-gitconfig.c
@@ -341,6 +341,13 @@ main(int argc, char *argv[])
 		got_privsep_send_error(&ibuf, err);
 		return 1;
 	}
+
+	/* revoke fs access */
+	if (landlock_no_fs() == -1) {
+		err = got_error_from_errno("landlock_no_fs");
+		got_privsep_send_error(&ibuf, err);
+		return 1;
+	}
 #endif
 
 	for (;;) {
blob - 69f6999b8df42a9f230c521287de6e5aadebd128
blob + 3b954345ac46a733c1c785bd2af8facdac0a4f34
--- libexec/got-read-gotconfig/got-read-gotconfig.c
+++ libexec/got-read-gotconfig/got-read-gotconfig.c
@@ -498,6 +498,13 @@ main(int argc, char *argv[])
 		got_privsep_send_error(&ibuf, err);
 		return 1;
 	}
+
+	/* revoke fs access */
+	if (landlock_no_fs() == -1) {
+		err = got_error_from_errno("landlock_no_fs");
+		got_privsep_send_error(&ibuf, err);
+		return 1;
+	}
 #endif
 
 	if (argc > 1)
blob - 3d9bc64ad66ca532a2c58b8d50e3d4ab51abb4db
blob + dc0a31bec0e6ec9ca5b23fbc47165af5c10063e5
--- libexec/got-read-object/got-read-object.c
+++ libexec/got-read-object/got-read-object.c
@@ -140,6 +140,13 @@ main(int argc, char *argv[])
 		got_privsep_send_error(&ibuf, err);
 		return 1;
 	}
+
+	/* revoke fs access */
+	if (landlock_no_fs() == -1) {
+		err = got_error_from_errno("landlock_no_fs");
+		got_privsep_send_error(&ibuf, err);
+		return 1;
+	}
 #endif
 
 	for (;;) {
blob - 760a54783d11db6cc8fed461bc956854e6b5f2ed
blob + 722e0c736645f1324e288c3f065a34ec6f45c449
--- libexec/got-read-pack/got-read-pack.c
+++ libexec/got-read-pack/got-read-pack.c
@@ -1031,6 +1031,13 @@ main(int argc, char *argv[])
 		got_privsep_send_error(&ibuf, err);
 		return 1;
 	}
+
+	/* revoke fs access */
+	if (landlock_no_fs() == -1) {
+		err = got_error_from_errno("landlock_no_fs");
+		got_privsep_send_error(&ibuf, err);
+		return 1;
+	}
 #endif
 
 	err = receive_packidx(&packidx, &ibuf);
blob - 870e8ca6c8d4439248bc960e5d6797861de4de07
blob + 57787944b6605bdc56c8281731a46bb5a54f9442
--- libexec/got-read-tag/got-read-tag.c
+++ libexec/got-read-tag/got-read-tag.c
@@ -114,6 +114,13 @@ main(int argc, char *argv[])
 		got_privsep_send_error(&ibuf, err);
 		return 1;
 	}
+
+	/* revoke fs access */
+	if (landlock_no_fs() == -1) {
+		err = got_error_from_errno("landlock_no_fs");
+		got_privsep_send_error(&ibuf, err);
+		return 1;
+	}
 #endif
 
 	for (;;) {
blob - 35323190d763a2a21c96e0b0f6c3d19f6687f007
blob + 7a53a1be870ee3435986176c3800ecefc8647a04
--- libexec/got-read-tree/got-read-tree.c
+++ libexec/got-read-tree/got-read-tree.c
@@ -113,6 +113,13 @@ main(int argc, char *argv[])
 		got_privsep_send_error(&ibuf, err);
 		return 1;
 	}
+
+	/* revoke fs access */
+	if (landlock_no_fs() == -1) {
+		err = got_error_from_errno("landlock_no_fs");
+		got_privsep_send_error(&ibuf, err);
+		return 1;
+	}
 #endif
 
 	for (;;) {
blob - 5a7564d43fbe801786356a9a6036bb9372e66c68
blob + be27709918c6e0c9c853297e6344ade339339ed4
--- libexec/got-send-pack/got-send-pack.c
+++ libexec/got-send-pack/got-send-pack.c
@@ -599,6 +599,13 @@ main(int argc, char **argv)
 		got_privsep_send_error(&ibuf, err);
 		return 1;
 	}
+
+	/* revoke fs access */
+	if (landlock_no_fs() == -1) {
+		err = got_error_from_errno("landlock_no_fs");
+		got_privsep_send_error(&ibuf, err);
+		return 1;
+	}
 #endif
 	if ((err = got_privsep_recv_imsg(&imsg, &ibuf, 0)) != 0) {
 		if (err->code == GOT_ERR_PRIVSEP_PIPE)