Download raw body.
[got-portable] landlock support, second try
Thomas Adam <thomas@xteddy.org> writes:
> On Sun, Feb 06, 2022 at 12:06:27PM +0100, Omar Polo wrote:
>> here's a revised diff. it's equivalent in practice to the previous one,
>> but hopefully less scary :)
>
> Thanks for this. I have no means of testing this though (the kernel version I
> have here on Arch Linux doesn't seem to offer Landlock) but I have a few
> comment in-line below.
unfortunately it doesn't seem to be that much available yet. I can
confirm that fedora has it, and I'm told nixos ship with landlock
enabled too.
I just tried on a devuan ceres (unstable) vm and they ship
linux/landlock.h, but the actual kernel has landlock disabled! I've
added a check for ENOSYS and ENOTSUP to handle this situation where
landlock was found at compile time but it's not present at runtime.
op@devuan:~$ uname -a
Linux devuan 5.15.0-3-amd64 #1 SMP Debian 5.15.15-1 (2022-01-18) x86_64 GNU/Linux
>> P.S.: now that I think of it, there's still a thing that can be
>> improved. I went with compat/landlock.c because it was an easy way to
>> add the support, but should we move that file elsewhere?
>
> I've addressed this in a different reply in this thread.
agreed on your reasoning
>> +#ifdef HAVE_LINUX_LANDLOCK_H
>> + /* 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
>> +#endif
>
> Is the main interface to landlock via landlock_no_fs() in all cases where
> we're using it here? If so, perhaps it would be better to do this in
> got_compat.h:
>
> #ifndef HAVE_LINUX_LANDLOCK_H
> #define landlock_no_fs() (0)
> #endif
>
> That way, the difference in peppering the main codebase shrinks, meaning we
> won't have too many merge conflicts in the future.
agreed, and makes the diff shorter too! :)
> Kindly,
> Thomas
Cheers
Omar Polo
diff 1f480907e29bc783454427371277ef33a25658e4 /home/op/w/got-portable
blob - 958a3d67dfe92ddf1caf9fd8e3586f887a36001b
file + compat/Makefile.am
--- 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
file + compat/landlock.c
--- /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
file + configure.ac
--- 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
file + include/got_compat.h
--- include/got_compat.h
+++ include/got_compat.h
@@ -43,6 +43,12 @@
#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
#define INFTIM -1
#endif
blob - 65c075409a0f6850f37b585385b6429b80a143ed
file + libexec/got-fetch-pack/got-fetch-pack.c
--- 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
file + libexec/got-index-pack/got-index-pack.c
--- 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
file + libexec/got-read-blob/got-read-blob.c
--- 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
file + libexec/got-read-commit/got-read-commit.c
--- 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
file + libexec/got-read-gitconfig/got-read-gitconfig.c
--- 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
file + libexec/got-read-gotconfig/got-read-gotconfig.c
--- 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
file + libexec/got-read-object/got-read-object.c
--- 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
file + libexec/got-read-pack/got-read-pack.c
--- 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
file + libexec/got-read-tag/got-read-tag.c
--- 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
file + libexec/got-read-tree/got-read-tree.c
--- 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
file + libexec/got-send-pack/got-send-pack.c
--- 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)
[got-portable] landlock support, second try