From 75f615905629f64f40363161281d640010153d64 Mon Sep 17 00:00:00 2001 From: shtrophic Date: Tue, 12 Nov 2024 21:01:09 +0100 Subject: sandboxing port to linux via landlock --- Makefile | 4 +- data.c | 39 +------------ sandbox.c | 184 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ snac.h | 2 + 4 files changed, 190 insertions(+), 39 deletions(-) create mode 100644 sandbox.c diff --git a/Makefile b/Makefile index 600419d..225031a 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ CFLAGS?=-g -Wall -Wextra -pedantic all: snac -snac: snac.o main.o data.o http.o httpd.o webfinger.o \ +snac: snac.o main.o sandbox.o data.o http.o httpd.o webfinger.o \ activitypub.o html.o utils.o format.o upgrade.o mastoapi.o $(CC) $(CFLAGS) -L/usr/local/lib *.o -lcurl -lcrypto $(LDFLAGS) -pthread -o $@ @@ -36,6 +36,8 @@ uninstall: activitypub.o: activitypub.c xs.h xs_json.h xs_curl.h xs_mime.h \ xs_openssl.h xs_regex.h xs_time.h xs_set.h xs_match.h snac.h \ http_codes.h +sandbox.o: sandbox.c xs.h xs_hex.h xs_io.h xs_json.h xs_openssl.h \ + xs_glob.h xs_set.h xs_time.h xs_regex.h xs_match.h xs_unicode.h snac.h data.o: data.c xs.h xs_hex.h xs_io.h xs_json.h xs_openssl.h xs_glob.h \ xs_set.h xs_time.h xs_regex.h xs_match.h xs_unicode.h xs_random.h snac.h \ http_codes.h diff --git a/data.c b/data.c index 1cd69a5..54099db 100644 --- a/data.c +++ b/data.c @@ -115,44 +115,7 @@ int srv_open(const char *basedir, int auto_upgrade) #define st_mtim st_mtimespec #endif -#ifdef __OpenBSD__ - if (xs_is_true(xs_dict_get(srv_config, "disable_openbsd_security"))) { - srv_debug(1, xs_dup("OpenBSD security disabled by admin")); - } - else { - int smail = !xs_is_true(xs_dict_get(srv_config, "disable_email_notifications")); - const char *address = xs_dict_get(srv_config, "address"); - - srv_debug(1, xs_fmt("Calling unveil()")); - unveil(basedir, "rwc"); - unveil("/tmp", "rwc"); - unveil("/etc/resolv.conf", "r"); - unveil("/etc/hosts", "r"); - unveil("/etc/ssl/openssl.cnf", "r"); - unveil("/etc/ssl/cert.pem", "r"); - unveil("/usr/share/zoneinfo", "r"); - - if (smail) - unveil("/usr/sbin/sendmail", "x"); - - if (*address == '/') - unveil(address, "rwc"); - - unveil(NULL, NULL); - - srv_debug(1, xs_fmt("Calling pledge()")); - - xs *p = xs_str_new("stdio rpath wpath cpath flock inet proc dns fattr"); - - if (smail) - p = xs_str_cat(p, " exec"); - - if (*address == '/') - p = xs_str_cat(p, " unix"); - - pledge(p, NULL); - } -#endif /* __OpenBSD__ */ + sbox_enter(srv_basedir); /* read (and drop) emojis.json, possibly creating it */ xs_free(emojis()); diff --git a/sandbox.c b/sandbox.c new file mode 100644 index 0000000..f83a947 --- /dev/null +++ b/sandbox.c @@ -0,0 +1,184 @@ +#include "xs.h" + +#include "snac.h" + +#include + +#if defined (__linux__) +# define __USE_GNU +# include +# include +# include +# include +# include +# include +#endif + +void sbox_enter(const char *basedir) +{ + if (xs_is_true(xs_dict_get(srv_config, "disable_openbsd_security"))) { + srv_log(xs_dup("disable_openbsd_security is deprecated. Use disable_sandbox instead.")); + return; + } + if (xs_is_true(xs_dict_get(srv_config, "disable_sandbox"))) { + srv_debug(0, xs_dup("Sandbox disabled by admin")); + return; + } + + const char *address = xs_dict_get(srv_config, "address"); + +#if defined (__OpenBSD__) + int smail = !xs_is_true(xs_dict_get(srv_config, "disable_email_notifications")); + + srv_debug(1, xs_fmt("Calling unveil()")); + unveil(basedir, "rwc"); + unveil("/tmp", "rwc"); + unveil("/etc/resolv.conf", "r"); + unveil("/etc/hosts", "r"); + unveil("/etc/ssl/openssl.cnf", "r"); + unveil("/etc/ssl/cert.pem", "r"); + unveil("/usr/share/zoneinfo", "r"); + + if (smail) + unveil("/usr/sbin/sendmail", "x"); + + if (*address == '/') + unveil(address, "rwc"); + + unveil(NULL, NULL); + + srv_debug(1, xs_fmt("Calling pledge()")); + + xs *p = xs_str_new("stdio rpath wpath cpath flock inet proc dns fattr"); + + if (smail) + p = xs_str_cat(p, " exec"); + + if (*address == '/') + p = xs_str_cat(p, " unix"); + + pledge(p, NULL); + + xs_free(p); +#elif defined (__linux__) + int error, ruleset_fd, abi; + struct landlock_ruleset_attr rules = {0}; + struct landlock_path_beneath_attr path = {0}; + struct landlock_net_port_attr net = {0}; + + rules.handled_access_fs = + LANDLOCK_ACCESS_FS_EXECUTE | + LANDLOCK_ACCESS_FS_WRITE_FILE | + LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_REMOVE_DIR | + LANDLOCK_ACCESS_FS_REMOVE_FILE | + LANDLOCK_ACCESS_FS_MAKE_CHAR | + LANDLOCK_ACCESS_FS_MAKE_DIR | + LANDLOCK_ACCESS_FS_MAKE_REG | + LANDLOCK_ACCESS_FS_MAKE_SOCK | + LANDLOCK_ACCESS_FS_MAKE_FIFO | + LANDLOCK_ACCESS_FS_MAKE_BLOCK | + LANDLOCK_ACCESS_FS_MAKE_SYM | + LANDLOCK_ACCESS_FS_REFER | + LANDLOCK_ACCESS_FS_TRUNCATE | + LANDLOCK_ACCESS_FS_IOCTL_DEV; + rules.handled_access_net = + LANDLOCK_ACCESS_NET_BIND_TCP | + LANDLOCK_ACCESS_NET_CONNECT_TCP; + + abi = syscall(SYS_landlock_create_ruleset, NULL, 0, LANDLOCK_CREATE_RULESET_VERSION); + switch (abi) { + case -1: + srv_debug(0, xs_dup("Kernel without landlock support")); + return; + case 1: + rules.handled_access_fs &= ~LANDLOCK_ACCESS_FS_REFER; + __attribute__((fallthrough)); + case 2: + rules.handled_access_fs &= ~LANDLOCK_ACCESS_FS_TRUNCATE; + __attribute__((fallthrough)); + case 3: + rules.handled_access_net &= ~(LANDLOCK_ACCESS_NET_BIND_TCP | LANDLOCK_ACCESS_NET_CONNECT_TCP); + __attribute__((fallthrough)); + case 4: + rules.handled_access_fs &= ~LANDLOCK_ACCESS_FS_IOCTL_DEV; + } + srv_debug(1, xs_fmt("lanlock abi: %d", abi)); + + ruleset_fd = syscall(SYS_landlock_create_ruleset, &rules, sizeof(struct landlock_ruleset_attr), 0); + if (ruleset_fd == -1) { + srv_debug(0, xs_fmt("landlock_create_ruleset failed: %s", strerror(errno))); + return; + } + +#define LL_R LANDLOCK_ACCESS_FS_READ_FILE +#define LL_X LANDLOCK_ACCESS_FS_EXECUTE +#define LL_RWC (LL_R | LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_MAKE_REG | LANDLOCK_ACCESS_FS_TRUNCATE) +#define LL_UNX (LL_R | LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_MAKE_SOCK) +#define LL_CON LANDLOCK_ACCESS_NET_CONNECT_TCP +#define LL_BND LANDLOCK_ACCESS_NET_BIND_TCP + +#define LANDLOCK_PATH(p, r) do {\ + path.allowed_access = r;\ + if (abi < 3)\ + path.allowed_access &= ~LANDLOCK_ACCESS_FS_TRUNCATE;\ + path.parent_fd = open(p, O_PATH | O_CLOEXEC);\ + if (path.parent_fd == -1) {\ + srv_debug(2, xs_fmt("open %s: %s", p, strerror(errno)));\ + goto close;\ + }\ + error = syscall(SYS_landlock_add_rule, ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, &path, 0); \ + if (error) {\ + srv_debug(0, xs_fmt("LANDLOCK_PATH(%s): %s", p, strerror(errno)));\ + goto close;\ + }\ +} while (0) + +#define LANDLOCK_PORT(p, r) do {\ + uint16_t _p = p;\ + net.port = _p;\ + net.allowed_access = r;\ + error = syscall(SYS_landlock_add_rule, ruleset_fd, LANDLOCK_RULE_NET_PORT, &net, 0);\ + if (error) {\ + srv_debug(0, xs_fmt("LANDLOCK_PORT(%d): %s", _p, strerror(errno)));\ + goto close;\ + }\ +} while (0) + + LANDLOCK_PATH(basedir, LL_RWC); + LANDLOCK_PATH("/tmp", LL_RWC); + LANDLOCK_PATH("/dev/shm", LL_RWC); + LANDLOCK_PATH("/etc/resolv.conf", LL_R ); + LANDLOCK_PATH("/etc/hosts", LL_R ); + LANDLOCK_PATH("/etc/ssl/openssl.cnf", LL_R ); + LANDLOCK_PATH("/etc/ssl/cert.pem", LL_R ); + LANDLOCK_PATH("/usr/share/zoneinfo", LL_R ); + + if (*address == '/') + LANDLOCK_PATH(address, LL_UNX); + + if (abi > 3) { + if (*address != '/') { + LANDLOCK_PORT( + (uint16_t)xs_number_get(xs_dict_get(srv_config, "port")), LL_BND); + } + + LANDLOCK_PORT(80, LL_CON); + LANDLOCK_PORT(443, LL_CON); + } + + if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { + srv_debug(0, xs_fmt("prctl SET_NO_NEW_PRIVS: %s", strerror(errno))); + goto close; + } + + if (syscall(SYS_landlock_restrict_self, ruleset_fd, 0)) + srv_debug(0, xs_fmt("landlock_restrict_self: %s", strerror(errno))); + + srv_log(xs_dup("landlocked")); + +close: + close(ruleset_fd); + +#endif +} diff --git a/snac.h b/snac.h index ad2793e..ba84420 100644 --- a/snac.h +++ b/snac.h @@ -75,6 +75,8 @@ void snac_log(snac *user, xs_str *str); int srv_open(const char *basedir, int auto_upgrade); void srv_free(void); +void sbox_enter(const char *basedir); + int user_open(snac *snac, const char *uid); void user_free(snac *snac); xs_list *user_list(void); -- cgit v1.2.3 From 559f23c8080806e95a43a25f917762121fbbeee2 Mon Sep 17 00:00:00 2001 From: shtrophic Date: Sat, 16 Nov 2024 13:47:26 +0100 Subject: add distinction between RWC with directories and without, include FS_REFER permission --- sandbox.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/sandbox.c b/sandbox.c index f83a947..c8fbdaf 100644 --- a/sandbox.c +++ b/sandbox.c @@ -113,13 +113,16 @@ void sbox_enter(const char *basedir) #define LL_R LANDLOCK_ACCESS_FS_READ_FILE #define LL_X LANDLOCK_ACCESS_FS_EXECUTE -#define LL_RWC (LL_R | LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_MAKE_REG | LANDLOCK_ACCESS_FS_TRUNCATE) -#define LL_UNX (LL_R | LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_MAKE_SOCK) -#define LL_CON LANDLOCK_ACCESS_NET_CONNECT_TCP -#define LL_BND LANDLOCK_ACCESS_NET_BIND_TCP +#define LL_RWCF (LL_R | LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_MAKE_REG | LANDLOCK_ACCESS_FS_TRUNCATE | LANDLOCK_ACCESS_FS_REMOVE_FILE | LANDLOCK_ACCESS_FS_REFER) +#define LL_RWCD (LL_RWCF | LANDLOCK_ACCESS_FS_MAKE_DIR | LANDLOCK_ACCESS_FS_REMOVE_DIR) +#define LL_UNIX (LL_R | LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_MAKE_SOCK) +#define LL_CONN LANDLOCK_ACCESS_NET_CONNECT_TCP +#define LL_BIND LANDLOCK_ACCESS_NET_BIND_TCP #define LANDLOCK_PATH(p, r) do {\ path.allowed_access = r;\ + if (abi < 2)\ + path.allowed_access &= ~LANDLOCK_ACCESS_FS_REFER;\ if (abi < 3)\ path.allowed_access &= ~LANDLOCK_ACCESS_FS_TRUNCATE;\ path.parent_fd = open(p, O_PATH | O_CLOEXEC);\ @@ -145,9 +148,9 @@ void sbox_enter(const char *basedir) }\ } while (0) - LANDLOCK_PATH(basedir, LL_RWC); - LANDLOCK_PATH("/tmp", LL_RWC); - LANDLOCK_PATH("/dev/shm", LL_RWC); + LANDLOCK_PATH(basedir, LL_RWCD); + LANDLOCK_PATH("/tmp", LL_RWCD); + LANDLOCK_PATH("/dev/shm", LL_RWCF); LANDLOCK_PATH("/etc/resolv.conf", LL_R ); LANDLOCK_PATH("/etc/hosts", LL_R ); LANDLOCK_PATH("/etc/ssl/openssl.cnf", LL_R ); @@ -155,16 +158,16 @@ void sbox_enter(const char *basedir) LANDLOCK_PATH("/usr/share/zoneinfo", LL_R ); if (*address == '/') - LANDLOCK_PATH(address, LL_UNX); + LANDLOCK_PATH(address, LL_UNIX); if (abi > 3) { if (*address != '/') { LANDLOCK_PORT( - (uint16_t)xs_number_get(xs_dict_get(srv_config, "port")), LL_BND); + (uint16_t)xs_number_get(xs_dict_get(srv_config, "port")), LL_BIND); } - LANDLOCK_PORT(80, LL_CON); - LANDLOCK_PORT(443, LL_CON); + LANDLOCK_PORT(80, LL_CONN); + LANDLOCK_PORT(443, LL_CONN); } if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { -- cgit v1.2.3 From 017140f5235d5c379402715f2cbbe1fdd037ba16 Mon Sep 17 00:00:00 2001 From: shtrophic Date: Sat, 16 Nov 2024 13:50:16 +0100 Subject: remove unused headers --- sandbox.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sandbox.c b/sandbox.c index c8fbdaf..07a3094 100644 --- a/sandbox.c +++ b/sandbox.c @@ -7,11 +7,10 @@ #if defined (__linux__) # define __USE_GNU # include -# include # include # include +# include # include -# include #endif void sbox_enter(const char *basedir) -- cgit v1.2.3 From 972783fcb2d7855847f0ea0832da2abc71aa6b30 Mon Sep 17 00:00:00 2001 From: shtrophic Date: Tue, 19 Nov 2024 20:47:15 +0100 Subject: only rwc /dev/shm when WITHOUT_SHM is undefined --- sandbox.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sandbox.c b/sandbox.c index 07a3094..c45587a 100644 --- a/sandbox.c +++ b/sandbox.c @@ -149,7 +149,9 @@ void sbox_enter(const char *basedir) LANDLOCK_PATH(basedir, LL_RWCD); LANDLOCK_PATH("/tmp", LL_RWCD); +#ifndef WITHOUT_SHM LANDLOCK_PATH("/dev/shm", LL_RWCF); +#endif LANDLOCK_PATH("/etc/resolv.conf", LL_R ); LANDLOCK_PATH("/etc/hosts", LL_R ); LANDLOCK_PATH("/etc/ssl/openssl.cnf", LL_R ); -- cgit v1.2.3 From 80ff16b21c7081165d346ff94b450f432a82ee47 Mon Sep 17 00:00:00 2001 From: shtrophic Date: Tue, 19 Nov 2024 21:45:21 +0100 Subject: make sendmail executable if configured --- sandbox.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sandbox.c b/sandbox.c index c45587a..7f26d0a 100644 --- a/sandbox.c +++ b/sandbox.c @@ -26,9 +26,9 @@ void sbox_enter(const char *basedir) const char *address = xs_dict_get(srv_config, "address"); -#if defined (__OpenBSD__) int smail = !xs_is_true(xs_dict_get(srv_config, "disable_email_notifications")); +#if defined (__OpenBSD__) srv_debug(1, xs_fmt("Calling unveil()")); unveil(basedir, "rwc"); unveil("/tmp", "rwc"); @@ -161,6 +161,9 @@ void sbox_enter(const char *basedir) if (*address == '/') LANDLOCK_PATH(address, LL_UNIX); + if (smail) + LANDLOCK_PATH("/usr/sbin/sendmail", LL_X); + if (abi > 3) { if (*address != '/') { LANDLOCK_PORT( -- cgit v1.2.3 From e52b4bf39b7236b2a89e34aaf5c54db2e2b285d8 Mon Sep 17 00:00:00 2001 From: shtrophic Date: Thu, 5 Dec 2024 17:24:04 +0100 Subject: import landloc.h --- Makefile | 3 +- landloc.h | 153 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ sandbox.c | 173 ++++++++++++++++---------------------------------------------- 3 files changed, 199 insertions(+), 130 deletions(-) create mode 100644 landloc.h diff --git a/Makefile b/Makefile index 225031a..2b89cfa 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,8 @@ activitypub.o: activitypub.c xs.h xs_json.h xs_curl.h xs_mime.h \ xs_openssl.h xs_regex.h xs_time.h xs_set.h xs_match.h snac.h \ http_codes.h sandbox.o: sandbox.c xs.h xs_hex.h xs_io.h xs_json.h xs_openssl.h \ - xs_glob.h xs_set.h xs_time.h xs_regex.h xs_match.h xs_unicode.h snac.h + xs_glob.h xs_set.h xs_time.h xs_regex.h xs_match.h xs_unicode.h \ + landloc.h snac.h data.o: data.c xs.h xs_hex.h xs_io.h xs_json.h xs_openssl.h xs_glob.h \ xs_set.h xs_time.h xs_regex.h xs_match.h xs_unicode.h xs_random.h snac.h \ http_codes.h diff --git a/landloc.h b/landloc.h new file mode 100644 index 0000000..c5b849a --- /dev/null +++ b/landloc.h @@ -0,0 +1,153 @@ +/** + * Zero-Clause BSD + * =============== + * + * Copyright 2024 shtrophic + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted. + * + * 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. + * + */ + +/** + * Usage example: + * + +LL_BEGIN(my_sandbox_function, const char *rw_path) { + + LL_PATH(rw_path, LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_READ_DIR | LANDLOCK_ACCESS_FS_EXECUTE); + LL_PORT(443, LANDLOCK_ACCESS_NET_CONNECT_TCP); + +} LL_END + +int main(void) { + + int status = my_sandbox_function("some/path"); + + if (status != 0) { + // error + } + +} + */ + +#ifndef __LANDLOC_H__ +#define __LANDLOC_H__ + +#ifndef __linux__ +#error "no landlock without linux" +#endif + +#include +#include +#include +#include +#include + +#ifndef O_PATH +#define O_PATH 010000000 +#endif + +#ifndef LL_PRINTERR +#define LL_PRINTERR(fmt, ...) (void)fmt; +#else +#include +#include +#endif + +#define LL_FS_ALL (\ + LANDLOCK_ACCESS_FS_EXECUTE |\ + LANDLOCK_ACCESS_FS_WRITE_FILE |\ + LANDLOCK_ACCESS_FS_READ_FILE |\ + LANDLOCK_ACCESS_FS_READ_DIR |\ + LANDLOCK_ACCESS_FS_REMOVE_DIR |\ + LANDLOCK_ACCESS_FS_REMOVE_FILE |\ + LANDLOCK_ACCESS_FS_MAKE_CHAR |\ + LANDLOCK_ACCESS_FS_MAKE_DIR |\ + LANDLOCK_ACCESS_FS_MAKE_REG |\ + LANDLOCK_ACCESS_FS_MAKE_SOCK |\ + LANDLOCK_ACCESS_FS_MAKE_FIFO |\ + LANDLOCK_ACCESS_FS_MAKE_BLOCK |\ + LANDLOCK_ACCESS_FS_MAKE_SYM |\ + LANDLOCK_ACCESS_FS_REFER |\ + LANDLOCK_ACCESS_FS_TRUNCATE |\ + LANDLOCK_ACCESS_FS_IOCTL_DEV ) + +#define LL_NET_ALL (\ + LANDLOCK_ACCESS_NET_BIND_TCP |\ + LANDLOCK_ACCESS_NET_CONNECT_TCP ) + +#define LL_BEGIN(function, ...) int function(__VA_ARGS__) {\ + int ll_rule_fd, ll_abi;\ + struct landlock_ruleset_attr __rattr = {0};\ + struct landlock_path_beneath_attr __pattr = {0};\ + struct landlock_net_port_attr __nattr = {0};\ + int __err = 0;\ + __rattr.handled_access_fs = LL_FS_ALL;\ + __rattr.handled_access_net = LL_NET_ALL;\ + ll_abi = (int)syscall(SYS_landlock_create_ruleset, NULL, 0, LANDLOCK_CREATE_RULESET_VERSION);\ + switch (ll_abi) {\ + case -1: return -1;\ + case 1: __rattr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_REFER; __attribute__((fallthrough));\ + case 2: __rattr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_TRUNCATE; __attribute__((fallthrough));\ + case 3: __rattr.handled_access_net &= ~(LANDLOCK_ACCESS_NET_BIND_TCP | LANDLOCK_ACCESS_NET_CONNECT_TCP); __attribute__((fallthrough));\ + case 4: __rattr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_IOCTL_DEV;\ + default: break;\ + }\ + ll_rule_fd = (int)syscall(SYS_landlock_create_ruleset, &__rattr, sizeof(struct landlock_ruleset_attr), 0);\ + if (-1 == ll_rule_fd) {\ + LL_PRINTERR("landlock_create_ruleset: %s", strerror(errno));\ + return -1;\ + } + +#define LL_END \ + __err = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);\ + if (-1 == __err) {\ + LL_PRINTERR("set_no_new_privs: %s", strerror(errno));\ + goto __close;\ + }\ + __err = (int)syscall(SYS_landlock_restrict_self, ll_rule_fd, 0);\ + if (__err)\ + LL_PRINTERR("landlock_restrict_self: %s", strerror(errno));\ + __close: close(ll_rule_fd);\ + return __err; } + +#define LL_PATH(p, rules) do {\ + const char *__path = (p);\ + __pattr.allowed_access = (rules) & __rattr.handled_access_fs;\ + __pattr.parent_fd = open(__path, O_PATH | O_CLOEXEC);\ + if (-1 == __pattr.parent_fd) {\ + LL_PRINTERR("open(%s): %s", __path, strerror(errno));\ + __err = -1;\ + goto __close;\ + }\ + __err = (int)syscall(SYS_landlock_add_rule, ll_rule_fd, LANDLOCK_RULE_PATH_BENEATH, &__pattr, 0);\ + if (__err) {\ + LL_PRINTERR("landlock_add_rule(%s): %s", __path, strerror(errno));\ + goto __close;\ + }\ + close(__pattr.parent_fd);\ +} while (0) + +#define LL_PORT(p, rules) do {\ + if (ll_abi > 3) {\ + unsigned short __port = (p);\ + __nattr.allowed_access = (rules);\ + __nattr.port = __port;\ + __err = (int)syscall(SYS_landlock_add_rule, ll_rule_fd, LANDLOCK_RULE_NET_PORT, &__nattr, 0);\ + if (__err) {\ + LL_PRINTERR("landlock_add_rule(%u): %s", __port, strerror(errno));\ + goto __close;\ + }\ + }\ +} while (0) + +#endif /* __LANDLOC_H__ */ diff --git a/sandbox.c b/sandbox.c index 7f26d0a..6dd9360 100644 --- a/sandbox.c +++ b/sandbox.c @@ -5,12 +5,49 @@ #include #if defined (__linux__) -# define __USE_GNU -# include -# include -# include -# include -# include + +#define LL_PRINTERR(fmt, ...) srv_debug(0, xs_fmt(fmt, __VA_ARGS__)) +#include "landloc.h" + +#define LL_R LANDLOCK_ACCESS_FS_READ_FILE +#define LL_X LANDLOCK_ACCESS_FS_EXECUTE +#define LL_RWCF (LL_R | LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_MAKE_REG | LANDLOCK_ACCESS_FS_TRUNCATE | LANDLOCK_ACCESS_FS_REMOVE_FILE | LANDLOCK_ACCESS_FS_REFER) +#define LL_RWCD (LL_RWCF | LANDLOCK_ACCESS_FS_MAKE_DIR | LANDLOCK_ACCESS_FS_REMOVE_DIR) +#define LL_UNIX (LL_R | LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_MAKE_SOCK) +#define LL_CONN LANDLOCK_ACCESS_NET_CONNECT_TCP +#define LL_BIND LANDLOCK_ACCESS_NET_BIND_TCP + +static +LL_BEGIN(sbox_enter_linux_, const char* basedir, const char *address, int smail) { + + LL_PATH(basedir, LL_RWCD); + LL_PATH("/tmp", LL_RWCD); +#ifndef WITHOUT_SHM + LL_PATH("/dev/shm", LL_RWCF); +#endif + LL_PATH("/etc/resolv.conf", LL_R ); + LL_PATH("/etc/hosts", LL_R ); + LL_PATH("/etc/ssl/openssl.cnf", LL_R ); + LL_PATH("/etc/ssl/cert.pem", LL_R ); + LL_PATH("/usr/share/zoneinfo", LL_R ); + + if (*address == '/') + LL_PATH(address, LL_UNIX); + + if (smail) + LL_PATH("/usr/sbin/sendmail", LL_X); + + + if (*address != '/') { + LL_PORT( + (unsigned short)xs_number_get(xs_dict_get(srv_config, "port")), LL_BIND); + } + + LL_PORT(80, LL_CONN); + LL_PORT(443, LL_CONN); + +} LL_END + #endif void sbox_enter(const char *basedir) @@ -60,132 +97,10 @@ void sbox_enter(const char *basedir) xs_free(p); #elif defined (__linux__) - int error, ruleset_fd, abi; - struct landlock_ruleset_attr rules = {0}; - struct landlock_path_beneath_attr path = {0}; - struct landlock_net_port_attr net = {0}; - - rules.handled_access_fs = - LANDLOCK_ACCESS_FS_EXECUTE | - LANDLOCK_ACCESS_FS_WRITE_FILE | - LANDLOCK_ACCESS_FS_READ_FILE | - LANDLOCK_ACCESS_FS_REMOVE_DIR | - LANDLOCK_ACCESS_FS_REMOVE_FILE | - LANDLOCK_ACCESS_FS_MAKE_CHAR | - LANDLOCK_ACCESS_FS_MAKE_DIR | - LANDLOCK_ACCESS_FS_MAKE_REG | - LANDLOCK_ACCESS_FS_MAKE_SOCK | - LANDLOCK_ACCESS_FS_MAKE_FIFO | - LANDLOCK_ACCESS_FS_MAKE_BLOCK | - LANDLOCK_ACCESS_FS_MAKE_SYM | - LANDLOCK_ACCESS_FS_REFER | - LANDLOCK_ACCESS_FS_TRUNCATE | - LANDLOCK_ACCESS_FS_IOCTL_DEV; - rules.handled_access_net = - LANDLOCK_ACCESS_NET_BIND_TCP | - LANDLOCK_ACCESS_NET_CONNECT_TCP; - - abi = syscall(SYS_landlock_create_ruleset, NULL, 0, LANDLOCK_CREATE_RULESET_VERSION); - switch (abi) { - case -1: - srv_debug(0, xs_dup("Kernel without landlock support")); - return; - case 1: - rules.handled_access_fs &= ~LANDLOCK_ACCESS_FS_REFER; - __attribute__((fallthrough)); - case 2: - rules.handled_access_fs &= ~LANDLOCK_ACCESS_FS_TRUNCATE; - __attribute__((fallthrough)); - case 3: - rules.handled_access_net &= ~(LANDLOCK_ACCESS_NET_BIND_TCP | LANDLOCK_ACCESS_NET_CONNECT_TCP); - __attribute__((fallthrough)); - case 4: - rules.handled_access_fs &= ~LANDLOCK_ACCESS_FS_IOCTL_DEV; - } - srv_debug(1, xs_fmt("lanlock abi: %d", abi)); - - ruleset_fd = syscall(SYS_landlock_create_ruleset, &rules, sizeof(struct landlock_ruleset_attr), 0); - if (ruleset_fd == -1) { - srv_debug(0, xs_fmt("landlock_create_ruleset failed: %s", strerror(errno))); - return; - } - -#define LL_R LANDLOCK_ACCESS_FS_READ_FILE -#define LL_X LANDLOCK_ACCESS_FS_EXECUTE -#define LL_RWCF (LL_R | LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_MAKE_REG | LANDLOCK_ACCESS_FS_TRUNCATE | LANDLOCK_ACCESS_FS_REMOVE_FILE | LANDLOCK_ACCESS_FS_REFER) -#define LL_RWCD (LL_RWCF | LANDLOCK_ACCESS_FS_MAKE_DIR | LANDLOCK_ACCESS_FS_REMOVE_DIR) -#define LL_UNIX (LL_R | LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_MAKE_SOCK) -#define LL_CONN LANDLOCK_ACCESS_NET_CONNECT_TCP -#define LL_BIND LANDLOCK_ACCESS_NET_BIND_TCP - -#define LANDLOCK_PATH(p, r) do {\ - path.allowed_access = r;\ - if (abi < 2)\ - path.allowed_access &= ~LANDLOCK_ACCESS_FS_REFER;\ - if (abi < 3)\ - path.allowed_access &= ~LANDLOCK_ACCESS_FS_TRUNCATE;\ - path.parent_fd = open(p, O_PATH | O_CLOEXEC);\ - if (path.parent_fd == -1) {\ - srv_debug(2, xs_fmt("open %s: %s", p, strerror(errno)));\ - goto close;\ - }\ - error = syscall(SYS_landlock_add_rule, ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, &path, 0); \ - if (error) {\ - srv_debug(0, xs_fmt("LANDLOCK_PATH(%s): %s", p, strerror(errno)));\ - goto close;\ - }\ -} while (0) - -#define LANDLOCK_PORT(p, r) do {\ - uint16_t _p = p;\ - net.port = _p;\ - net.allowed_access = r;\ - error = syscall(SYS_landlock_add_rule, ruleset_fd, LANDLOCK_RULE_NET_PORT, &net, 0);\ - if (error) {\ - srv_debug(0, xs_fmt("LANDLOCK_PORT(%d): %s", _p, strerror(errno)));\ - goto close;\ - }\ -} while (0) - - LANDLOCK_PATH(basedir, LL_RWCD); - LANDLOCK_PATH("/tmp", LL_RWCD); -#ifndef WITHOUT_SHM - LANDLOCK_PATH("/dev/shm", LL_RWCF); -#endif - LANDLOCK_PATH("/etc/resolv.conf", LL_R ); - LANDLOCK_PATH("/etc/hosts", LL_R ); - LANDLOCK_PATH("/etc/ssl/openssl.cnf", LL_R ); - LANDLOCK_PATH("/etc/ssl/cert.pem", LL_R ); - LANDLOCK_PATH("/usr/share/zoneinfo", LL_R ); - - if (*address == '/') - LANDLOCK_PATH(address, LL_UNIX); - - if (smail) - LANDLOCK_PATH("/usr/sbin/sendmail", LL_X); - - if (abi > 3) { - if (*address != '/') { - LANDLOCK_PORT( - (uint16_t)xs_number_get(xs_dict_get(srv_config, "port")), LL_BIND); - } - - LANDLOCK_PORT(80, LL_CONN); - LANDLOCK_PORT(443, LL_CONN); - } - if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { - srv_debug(0, xs_fmt("prctl SET_NO_NEW_PRIVS: %s", strerror(errno))); - goto close; - } - - if (syscall(SYS_landlock_restrict_self, ruleset_fd, 0)) - srv_debug(0, xs_fmt("landlock_restrict_self: %s", strerror(errno))); + sbox_enter_linux_(basedir, address, smail); srv_log(xs_dup("landlocked")); -close: - close(ruleset_fd); - #endif } -- cgit v1.2.3 From 43947cce0c22c0c5a2f3b9b70a8d48dd72e2f02b Mon Sep 17 00:00:00 2001 From: shtrophic Date: Sat, 7 Dec 2024 17:17:18 +0100 Subject: update landloc.h --- landloc.h | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/landloc.h b/landloc.h index c5b849a..e1ade20 100644 --- a/landloc.h +++ b/landloc.h @@ -18,9 +18,19 @@ */ /** - * Usage example: - * + * Repository: https://git.sr.ht/~shtrophic/landloc.h + */ +/** + * Usage: + * + * Define a sandboxing function using the LL_BEGIN(...) and LL_END macros. + * the arguments of LL_BEGIN are the function's signature. + * Between those macros, implement your sandbox using LL_PATH() and LL_PORT() macros. + * Calling LL_PATH() and LL_PORT() anywhere else will not work. + * You may prepend `static` before LL_BEGIN to make the function static. + * You need (should) wrap your sandboxing code in another set of braces: + * LL_BEGIN(my_sandbox_function, const char *rw_path) { LL_PATH(rw_path, LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_READ_DIR | LANDLOCK_ACCESS_FS_EXECUTE); @@ -28,6 +38,10 @@ LL_BEGIN(my_sandbox_function, const char *rw_path) { } LL_END + * + * Then, call it in your application's code. + * + int main(void) { int status = my_sandbox_function("some/path"); @@ -37,6 +51,14 @@ int main(void) { } } + + * + * You may define LL_PRINTERR(fmt, ...) before including this header to enable debug output: + * + +#define LL_PRINTERR(fmt, ...) fprintf(stderr, fmt "\n", __VA_ARGS__) +#include "landloc.h" + */ #ifndef __LANDLOC_H__ @@ -138,9 +160,9 @@ int main(void) { } while (0) #define LL_PORT(p, rules) do {\ + unsigned short __port = (p);\ + __nattr.allowed_access = (rules);\ if (ll_abi > 3) {\ - unsigned short __port = (p);\ - __nattr.allowed_access = (rules);\ __nattr.port = __port;\ __err = (int)syscall(SYS_landlock_add_rule, ll_rule_fd, LANDLOCK_RULE_NET_PORT, &__nattr, 0);\ if (__err) {\ -- cgit v1.2.3 From 7d07d3bffd2994055165d10a57e93327fc86d961 Mon Sep 17 00:00:00 2001 From: shtrophic Date: Sun, 8 Dec 2024 08:48:44 +0100 Subject: cleanup rules --- sandbox.c | 52 +++++++++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/sandbox.c b/sandbox.c index 6dd9360..abced68 100644 --- a/sandbox.c +++ b/sandbox.c @@ -9,42 +9,48 @@ #define LL_PRINTERR(fmt, ...) srv_debug(0, xs_fmt(fmt, __VA_ARGS__)) #include "landloc.h" -#define LL_R LANDLOCK_ACCESS_FS_READ_FILE -#define LL_X LANDLOCK_ACCESS_FS_EXECUTE -#define LL_RWCF (LL_R | LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_MAKE_REG | LANDLOCK_ACCESS_FS_TRUNCATE | LANDLOCK_ACCESS_FS_REMOVE_FILE | LANDLOCK_ACCESS_FS_REFER) -#define LL_RWCD (LL_RWCF | LANDLOCK_ACCESS_FS_MAKE_DIR | LANDLOCK_ACCESS_FS_REMOVE_DIR) -#define LL_UNIX (LL_R | LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_MAKE_SOCK) -#define LL_CONN LANDLOCK_ACCESS_NET_CONNECT_TCP -#define LL_BIND LANDLOCK_ACCESS_NET_BIND_TCP - static LL_BEGIN(sbox_enter_linux_, const char* basedir, const char *address, int smail) { - LL_PATH(basedir, LL_RWCD); - LL_PATH("/tmp", LL_RWCD); + const unsigned long long + r = LANDLOCK_ACCESS_FS_READ_DIR | + LANDLOCK_ACCESS_FS_READ_FILE, + w = LANDLOCK_ACCESS_FS_WRITE_FILE | + LANDLOCK_ACCESS_FS_TRUNCATE, + c = LANDLOCK_ACCESS_FS_MAKE_DIR | + LANDLOCK_ACCESS_FS_MAKE_REG | + LANDLOCK_ACCESS_FS_TRUNCATE | + LANDLOCK_ACCESS_FS_MAKE_SYM | + LANDLOCK_ACCESS_FS_REMOVE_DIR | + LANDLOCK_ACCESS_FS_REMOVE_FILE | + LANDLOCK_ACCESS_FS_REFER, + s = LANDLOCK_ACCESS_FS_MAKE_SOCK, + x = LANDLOCK_ACCESS_FS_EXECUTE; + + LL_PATH(basedir, r|w|c); + LL_PATH("/tmp", r|w|c); #ifndef WITHOUT_SHM - LL_PATH("/dev/shm", LL_RWCF); + LL_PATH("/dev/shm", r|w|c); #endif - LL_PATH("/etc/resolv.conf", LL_R ); - LL_PATH("/etc/hosts", LL_R ); - LL_PATH("/etc/ssl/openssl.cnf", LL_R ); - LL_PATH("/etc/ssl/cert.pem", LL_R ); - LL_PATH("/usr/share/zoneinfo", LL_R ); + LL_PATH("/etc/resolv.conf", r ); + LL_PATH("/etc/hosts", r ); + LL_PATH("/etc/ssl/openssl.cnf", r ); + LL_PATH("/etc/ssl/cert.pem", r ); + LL_PATH("/usr/share/zoneinfo", r ); if (*address == '/') - LL_PATH(address, LL_UNIX); + LL_PATH(address, s); if (smail) - LL_PATH("/usr/sbin/sendmail", LL_X); - + LL_PATH("/usr/sbin/sendmail", x); if (*address != '/') { - LL_PORT( - (unsigned short)xs_number_get(xs_dict_get(srv_config, "port")), LL_BIND); + unsigned short listen_port = xs_number_get(xs_dict_get(srv_config, "port")); + LL_PORT(listen_port, LANDLOCK_ACCESS_NET_BIND_TCP); } - LL_PORT(80, LL_CONN); - LL_PORT(443, LL_CONN); + LL_PORT(80, LANDLOCK_ACCESS_NET_CONNECT_TCP); + LL_PORT(443, LANDLOCK_ACCESS_NET_CONNECT_TCP); } LL_END -- cgit v1.2.3 From fb8145297c45c8fdfbdc3872c8345e51569a4a01 Mon Sep 17 00:00:00 2001 From: shtrophic Date: Sun, 8 Dec 2024 08:54:00 +0100 Subject: make log output specific to landlock status --- sandbox.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sandbox.c b/sandbox.c index abced68..3a5ca48 100644 --- a/sandbox.c +++ b/sandbox.c @@ -104,9 +104,10 @@ void sbox_enter(const char *basedir) xs_free(p); #elif defined (__linux__) - sbox_enter_linux_(basedir, address, smail); - - srv_log(xs_dup("landlocked")); + if (sbox_enter_linux_(basedir, address, smail) == 0) + srv_log(xs_dup("landlocked")); + else + srv_log(xs_dup("landlocking failed")); #endif } -- cgit v1.2.3 From f625b7f729c816ea17e69dfa5bf4c09399dece6f Mon Sep 17 00:00:00 2001 From: shtrophic Date: Sun, 8 Dec 2024 09:01:57 +0100 Subject: don't try to make files directory-readable --- sandbox.c | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/sandbox.c b/sandbox.c index 3a5ca48..6eafc43 100644 --- a/sandbox.c +++ b/sandbox.c @@ -13,30 +13,30 @@ static LL_BEGIN(sbox_enter_linux_, const char* basedir, const char *address, int smail) { const unsigned long long - r = LANDLOCK_ACCESS_FS_READ_DIR | - LANDLOCK_ACCESS_FS_READ_FILE, - w = LANDLOCK_ACCESS_FS_WRITE_FILE | - LANDLOCK_ACCESS_FS_TRUNCATE, - c = LANDLOCK_ACCESS_FS_MAKE_DIR | - LANDLOCK_ACCESS_FS_MAKE_REG | - LANDLOCK_ACCESS_FS_TRUNCATE | - LANDLOCK_ACCESS_FS_MAKE_SYM | - LANDLOCK_ACCESS_FS_REMOVE_DIR | - LANDLOCK_ACCESS_FS_REMOVE_FILE | - LANDLOCK_ACCESS_FS_REFER, - s = LANDLOCK_ACCESS_FS_MAKE_SOCK, - x = LANDLOCK_ACCESS_FS_EXECUTE; - - LL_PATH(basedir, r|w|c); - LL_PATH("/tmp", r|w|c); + rd = LANDLOCK_ACCESS_FS_READ_DIR, + rf = LANDLOCK_ACCESS_FS_READ_FILE, + w = LANDLOCK_ACCESS_FS_WRITE_FILE | + LANDLOCK_ACCESS_FS_TRUNCATE, + c = LANDLOCK_ACCESS_FS_MAKE_DIR | + LANDLOCK_ACCESS_FS_MAKE_REG | + LANDLOCK_ACCESS_FS_TRUNCATE | + LANDLOCK_ACCESS_FS_MAKE_SYM | + LANDLOCK_ACCESS_FS_REMOVE_DIR | + LANDLOCK_ACCESS_FS_REMOVE_FILE | + LANDLOCK_ACCESS_FS_REFER, + s = LANDLOCK_ACCESS_FS_MAKE_SOCK, + x = LANDLOCK_ACCESS_FS_EXECUTE; + + LL_PATH(basedir, rf|rd|w|c); + LL_PATH("/tmp", rf|rd|w|c); #ifndef WITHOUT_SHM - LL_PATH("/dev/shm", r|w|c); + LL_PATH("/dev/shm", rf|w|c ); #endif - LL_PATH("/etc/resolv.conf", r ); - LL_PATH("/etc/hosts", r ); - LL_PATH("/etc/ssl/openssl.cnf", r ); - LL_PATH("/etc/ssl/cert.pem", r ); - LL_PATH("/usr/share/zoneinfo", r ); + LL_PATH("/etc/resolv.conf", rf ); + LL_PATH("/etc/hosts", rf ); + LL_PATH("/etc/ssl/openssl.cnf", rf ); + LL_PATH("/etc/ssl/cert.pem", rf ); + LL_PATH("/usr/share/zoneinfo", rf ); if (*address == '/') LL_PATH(address, s); -- cgit v1.2.3 From 1a44f56372ac4ae821016e32daa7b23fbd4a93d4 Mon Sep 17 00:00:00 2001 From: shtrophic Date: Thu, 26 Dec 2024 15:22:39 +0100 Subject: import updated landloc.h --- landloc.h | 114 ++++++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 82 insertions(+), 32 deletions(-) diff --git a/landloc.h b/landloc.h index e1ade20..aaec29f 100644 --- a/landloc.h +++ b/landloc.h @@ -65,9 +65,13 @@ int main(void) { #define __LANDLOC_H__ #ifndef __linux__ -#error "no landlock without linux" +# error "no landlock without linux" #endif +#include + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 13, 0) + #include #include #include @@ -75,53 +79,89 @@ int main(void) { #include #ifndef O_PATH -#define O_PATH 010000000 +# define O_PATH 010000000 #endif #ifndef LL_PRINTERR -#define LL_PRINTERR(fmt, ...) (void)fmt; +# define LL_PRINTERR(fmt, ...) (void)fmt; #else -#include -#include +# include +# include #endif -#define LL_FS_ALL (\ - LANDLOCK_ACCESS_FS_EXECUTE |\ - LANDLOCK_ACCESS_FS_WRITE_FILE |\ - LANDLOCK_ACCESS_FS_READ_FILE |\ - LANDLOCK_ACCESS_FS_READ_DIR |\ - LANDLOCK_ACCESS_FS_REMOVE_DIR |\ - LANDLOCK_ACCESS_FS_REMOVE_FILE |\ - LANDLOCK_ACCESS_FS_MAKE_CHAR |\ - LANDLOCK_ACCESS_FS_MAKE_DIR |\ - LANDLOCK_ACCESS_FS_MAKE_REG |\ - LANDLOCK_ACCESS_FS_MAKE_SOCK |\ - LANDLOCK_ACCESS_FS_MAKE_FIFO |\ - LANDLOCK_ACCESS_FS_MAKE_BLOCK |\ - LANDLOCK_ACCESS_FS_MAKE_SYM |\ - LANDLOCK_ACCESS_FS_REFER |\ - LANDLOCK_ACCESS_FS_TRUNCATE |\ - LANDLOCK_ACCESS_FS_IOCTL_DEV ) - -#define LL_NET_ALL (\ - LANDLOCK_ACCESS_NET_BIND_TCP |\ - LANDLOCK_ACCESS_NET_CONNECT_TCP ) +#ifdef LANDLOCK_ACCESS_FS_REFER +# define __LL_FS_REFER_COMPAT LANDLOCK_ACCESS_FS_REFER +# define __LL_SWITCH_FS_REFER __rattr.handled_access_fs &= ~__LL_FS_REFER_COMPAT +#else +# define __LL_FS_REFER_COMPAT 0 +# define __LL_SWITCH_FS_REFER (void)0 +#endif + +#ifdef LANDLOCK_ACCESS_FS_TRUNCATE +# define __LL_FS_TRUNCATE_COMPAT LANDLOCK_ACCESS_FS_TRUNCATE +# define __LL_SWITCH_FS_TRUNCATE __rattr.handled_access_fs &= ~__LL_FS_TRUNCATE_COMPAT +#else +# define __LL_FS_TRUNCATE_COMPAT 0 +# define __LL_SWITCH_FS_TRUNCATE (void)0 +#endif + +#ifdef LANDLOCK_ACCESS_FS_IOCTL_DEV +# define __LL_FS_IOCTL_DEV_COMPAT LANDLOCK_ACCESS_FS_IOCTL_DEV +# define __LL_SWITCH_FS_IOCTL_DEV __rattr.handled_access_fs &= ~__LL_FS_IOCTL_DEV_COMPAT +#else +# define __LL_FS_IOCTL_DEV_COMPAT 0 +# define __LL_SWITCH_FS_IOCTL_DEV (void)0 +#endif + +#define LL_FS_ALL (\ + LANDLOCK_ACCESS_FS_EXECUTE |\ + LANDLOCK_ACCESS_FS_WRITE_FILE |\ + LANDLOCK_ACCESS_FS_READ_FILE |\ + LANDLOCK_ACCESS_FS_READ_DIR |\ + LANDLOCK_ACCESS_FS_REMOVE_DIR |\ + LANDLOCK_ACCESS_FS_REMOVE_FILE |\ + LANDLOCK_ACCESS_FS_MAKE_CHAR |\ + LANDLOCK_ACCESS_FS_MAKE_DIR |\ + LANDLOCK_ACCESS_FS_MAKE_REG |\ + LANDLOCK_ACCESS_FS_MAKE_SOCK |\ + LANDLOCK_ACCESS_FS_MAKE_FIFO |\ + LANDLOCK_ACCESS_FS_MAKE_BLOCK |\ + LANDLOCK_ACCESS_FS_MAKE_SYM |\ + __LL_FS_REFER_COMPAT |\ + __LL_FS_TRUNCATE_COMPAT |\ + __LL_FS_IOCTL_DEV_COMPAT ) + +#if defined(LANDLOCK_ACCESS_NET_BIND_TCP) && defined(LANDLOCK_ACCESS_NET_CONNECT_TCP) +# define __LL_HAVE_NET +#endif + +#ifdef __LL_HAVE_NET +# define LL_NET_ALL (LANDLOCK_ACCESS_NET_BIND_TCP | LANDLOCK_ACCESS_NET_CONNECT_TCP) +# define __LL_DECLARE_NET struct landlock_net_port_attr __nattr = {0} +# define __LL_INIT_NET __rattr.handled_access_net = LL_NET_ALL +# define __LL_SWITCH_NET do { __rattr.handled_access_net &= ~(LANDLOCK_ACCESS_NET_BIND_TCP | LANDLOCK_ACCESS_NET_CONNECT_TCP); } while (0) +#else +# define LL_NET_ALL 0 +# define __LL_DECLARE_NET (void)0 +# define __LL_INIT_NET (void)0 +# define __LL_SWITCH_NET (void)0 +#endif #define LL_BEGIN(function, ...) int function(__VA_ARGS__) {\ int ll_rule_fd, ll_abi;\ struct landlock_ruleset_attr __rattr = {0};\ struct landlock_path_beneath_attr __pattr = {0};\ - struct landlock_net_port_attr __nattr = {0};\ + __LL_DECLARE_NET;\ int __err = 0;\ __rattr.handled_access_fs = LL_FS_ALL;\ - __rattr.handled_access_net = LL_NET_ALL;\ + __LL_INIT_NET;\ ll_abi = (int)syscall(SYS_landlock_create_ruleset, NULL, 0, LANDLOCK_CREATE_RULESET_VERSION);\ switch (ll_abi) {\ case -1: return -1;\ - case 1: __rattr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_REFER; __attribute__((fallthrough));\ - case 2: __rattr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_TRUNCATE; __attribute__((fallthrough));\ - case 3: __rattr.handled_access_net &= ~(LANDLOCK_ACCESS_NET_BIND_TCP | LANDLOCK_ACCESS_NET_CONNECT_TCP); __attribute__((fallthrough));\ - case 4: __rattr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_IOCTL_DEV;\ + case 1: __LL_SWITCH_FS_REFER; __attribute__((fallthrough));\ + case 2: __LL_SWITCH_FS_TRUNCATE; __attribute__((fallthrough));\ + case 3: __LL_SWITCH_NET; __attribute__((fallthrough));\ + case 4: __LL_SWITCH_FS_IOCTL_DEV;\ default: break;\ }\ ll_rule_fd = (int)syscall(SYS_landlock_create_ruleset, &__rattr, sizeof(struct landlock_ruleset_attr), 0);\ @@ -159,6 +199,8 @@ int main(void) { close(__pattr.parent_fd);\ } while (0) +#ifdef __LL_HAVE_NET + #define LL_PORT(p, rules) do {\ unsigned short __port = (p);\ __nattr.allowed_access = (rules);\ @@ -172,4 +214,12 @@ int main(void) { }\ } while (0) +#else + +#define LL_PORT(p, rules) do { (void)p; (void)rules; } while (0) + +#endif /* __LL_HAVE_NET */ + +#endif /* KERNEL_VERSION(5, 13, 0) */ + #endif /* __LANDLOC_H__ */ -- cgit v1.2.3 From 629a7953f99191ac3b1d74f44ddd5b94e097adee Mon Sep 17 00:00:00 2001 From: shtrophic Date: Thu, 26 Dec 2024 15:53:51 +0100 Subject: use compat macros to compile on kernels without LANDLOCK_ACCESS_NET_* --- landloc.h | 96 ++++++++++++++++++++++++++++++++++----------------------------- sandbox.c | 6 ++-- 2 files changed, 55 insertions(+), 47 deletions(-) diff --git a/landloc.h b/landloc.h index aaec29f..8995871 100644 --- a/landloc.h +++ b/landloc.h @@ -90,57 +90,63 @@ int main(void) { #endif #ifdef LANDLOCK_ACCESS_FS_REFER -# define __LL_FS_REFER_COMPAT LANDLOCK_ACCESS_FS_REFER -# define __LL_SWITCH_FS_REFER __rattr.handled_access_fs &= ~__LL_FS_REFER_COMPAT +# define LANDLOCK_ACCESS_FS_REFER_COMPAT LANDLOCK_ACCESS_FS_REFER +# define __LL_SWITCH_FS_REFER __rattr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_REFER_COMPAT #else -# define __LL_FS_REFER_COMPAT 0 +# define LANDLOCK_ACCESS_FS_REFER_COMPAT 0 # define __LL_SWITCH_FS_REFER (void)0 #endif #ifdef LANDLOCK_ACCESS_FS_TRUNCATE -# define __LL_FS_TRUNCATE_COMPAT LANDLOCK_ACCESS_FS_TRUNCATE -# define __LL_SWITCH_FS_TRUNCATE __rattr.handled_access_fs &= ~__LL_FS_TRUNCATE_COMPAT +# define LANDLOCK_ACCESS_FS_TRUNCATE_COMPAT LANDLOCK_ACCESS_FS_TRUNCATE +# define __LL_SWITCH_FS_TRUNCATE __rattr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_TRUNCATE_COMPAT #else -# define __LL_FS_TRUNCATE_COMPAT 0 +# define LANDLOCK_ACCESS_FS_TRUNCATE_COMPAT 0 # define __LL_SWITCH_FS_TRUNCATE (void)0 #endif #ifdef LANDLOCK_ACCESS_FS_IOCTL_DEV -# define __LL_FS_IOCTL_DEV_COMPAT LANDLOCK_ACCESS_FS_IOCTL_DEV -# define __LL_SWITCH_FS_IOCTL_DEV __rattr.handled_access_fs &= ~__LL_FS_IOCTL_DEV_COMPAT +# define LANDLOCK_ACCESS_FS_IOCTL_DEV_COMPAT LANDLOCK_ACCESS_FS_IOCTL_DEV +# define __LL_SWITCH_FS_IOCTL_DEV __rattr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_IOCTL_DEV_COMPAT #else -# define __LL_FS_IOCTL_DEV_COMPAT 0 +# define LANDLOCK_ACCESS_FS_IOCTL_DEV_COMPAT 0 # define __LL_SWITCH_FS_IOCTL_DEV (void)0 #endif -#define LL_FS_ALL (\ - LANDLOCK_ACCESS_FS_EXECUTE |\ - LANDLOCK_ACCESS_FS_WRITE_FILE |\ - LANDLOCK_ACCESS_FS_READ_FILE |\ - LANDLOCK_ACCESS_FS_READ_DIR |\ - LANDLOCK_ACCESS_FS_REMOVE_DIR |\ - LANDLOCK_ACCESS_FS_REMOVE_FILE |\ - LANDLOCK_ACCESS_FS_MAKE_CHAR |\ - LANDLOCK_ACCESS_FS_MAKE_DIR |\ - LANDLOCK_ACCESS_FS_MAKE_REG |\ - LANDLOCK_ACCESS_FS_MAKE_SOCK |\ - LANDLOCK_ACCESS_FS_MAKE_FIFO |\ - LANDLOCK_ACCESS_FS_MAKE_BLOCK |\ - LANDLOCK_ACCESS_FS_MAKE_SYM |\ - __LL_FS_REFER_COMPAT |\ - __LL_FS_TRUNCATE_COMPAT |\ - __LL_FS_IOCTL_DEV_COMPAT ) +#define LL_FS_ALL (\ + LANDLOCK_ACCESS_FS_EXECUTE |\ + LANDLOCK_ACCESS_FS_WRITE_FILE |\ + LANDLOCK_ACCESS_FS_READ_FILE |\ + LANDLOCK_ACCESS_FS_READ_DIR |\ + LANDLOCK_ACCESS_FS_REMOVE_DIR |\ + LANDLOCK_ACCESS_FS_REMOVE_FILE |\ + LANDLOCK_ACCESS_FS_MAKE_CHAR |\ + LANDLOCK_ACCESS_FS_MAKE_DIR |\ + LANDLOCK_ACCESS_FS_MAKE_REG |\ + LANDLOCK_ACCESS_FS_MAKE_SOCK |\ + LANDLOCK_ACCESS_FS_MAKE_FIFO |\ + LANDLOCK_ACCESS_FS_MAKE_BLOCK |\ + LANDLOCK_ACCESS_FS_MAKE_SYM |\ + LANDLOCK_ACCESS_FS_REFER_COMPAT |\ + LANDLOCK_ACCESS_FS_TRUNCATE_COMPAT |\ + LANDLOCK_ACCESS_FS_IOCTL_DEV_COMPAT ) #if defined(LANDLOCK_ACCESS_NET_BIND_TCP) && defined(LANDLOCK_ACCESS_NET_CONNECT_TCP) -# define __LL_HAVE_NET -#endif +# define LL_HAVE_NET 1 + +# define LANDLOCK_ACCESS_NET_BIND_TCP_COMPAT LANDLOCK_ACCESS_NET_BIND_TCP +# define LANDLOCK_ACCESS_NET_CONNECT_TCP_COMPAT LANDLOCK_ACCESS_NET_CONNECT_TCP -#ifdef __LL_HAVE_NET -# define LL_NET_ALL (LANDLOCK_ACCESS_NET_BIND_TCP | LANDLOCK_ACCESS_NET_CONNECT_TCP) +# define LL_NET_ALL (LANDLOCK_ACCESS_NET_BIND_TCP_COMPAT | LANDLOCK_ACCESS_NET_CONNECT_TCP_COMPAT) # define __LL_DECLARE_NET struct landlock_net_port_attr __nattr = {0} # define __LL_INIT_NET __rattr.handled_access_net = LL_NET_ALL # define __LL_SWITCH_NET do { __rattr.handled_access_net &= ~(LANDLOCK_ACCESS_NET_BIND_TCP | LANDLOCK_ACCESS_NET_CONNECT_TCP); } while (0) #else +# define LL_HAVE_NET 0 + +# define LANDLOCK_ACCESS_NET_BIND_TCP_COMPAT 0 +# define LANDLOCK_ACCESS_NET_CONNECT_TCP_COMPAT 0 + # define LL_NET_ALL 0 # define __LL_DECLARE_NET (void)0 # define __LL_INIT_NET (void)0 @@ -185,26 +191,28 @@ int main(void) { #define LL_PATH(p, rules) do {\ const char *__path = (p);\ __pattr.allowed_access = (rules) & __rattr.handled_access_fs;\ - __pattr.parent_fd = open(__path, O_PATH | O_CLOEXEC);\ - if (-1 == __pattr.parent_fd) {\ - LL_PRINTERR("open(%s): %s", __path, strerror(errno));\ - __err = -1;\ - goto __close;\ - }\ - __err = (int)syscall(SYS_landlock_add_rule, ll_rule_fd, LANDLOCK_RULE_PATH_BENEATH, &__pattr, 0);\ - if (__err) {\ - LL_PRINTERR("landlock_add_rule(%s): %s", __path, strerror(errno));\ - goto __close;\ + if (__pattr.allowed_access != 0) {\ + __pattr.parent_fd = open(__path, O_PATH | O_CLOEXEC);\ + if (-1 == __pattr.parent_fd) {\ + LL_PRINTERR("open(%s): %s", __path, strerror(errno));\ + __err = -1;\ + goto __close;\ + }\ + __err = (int)syscall(SYS_landlock_add_rule, ll_rule_fd, LANDLOCK_RULE_PATH_BENEATH, &__pattr, 0);\ + if (__err) {\ + LL_PRINTERR("landlock_add_rule(%s): %s", __path, strerror(errno));\ + goto __close;\ + }\ + close(__pattr.parent_fd);\ }\ - close(__pattr.parent_fd);\ } while (0) -#ifdef __LL_HAVE_NET +#if LL_HAVE_NET #define LL_PORT(p, rules) do {\ unsigned short __port = (p);\ __nattr.allowed_access = (rules);\ - if (ll_abi > 3) {\ + if (ll_abi > 3 && __nattr.allowed_access != 0) {\ __nattr.port = __port;\ __err = (int)syscall(SYS_landlock_add_rule, ll_rule_fd, LANDLOCK_RULE_NET_PORT, &__nattr, 0);\ if (__err) {\ @@ -218,7 +226,7 @@ int main(void) { #define LL_PORT(p, rules) do { (void)p; (void)rules; } while (0) -#endif /* __LL_HAVE_NET */ +#endif /* LL_HAVE_NET */ #endif /* KERNEL_VERSION(5, 13, 0) */ diff --git a/sandbox.c b/sandbox.c index 6eafc43..b7c602e 100644 --- a/sandbox.c +++ b/sandbox.c @@ -46,11 +46,11 @@ LL_BEGIN(sbox_enter_linux_, const char* basedir, const char *address, int smail) if (*address != '/') { unsigned short listen_port = xs_number_get(xs_dict_get(srv_config, "port")); - LL_PORT(listen_port, LANDLOCK_ACCESS_NET_BIND_TCP); + LL_PORT(listen_port, LANDLOCK_ACCESS_NET_BIND_TCP_COMPAT); } - LL_PORT(80, LANDLOCK_ACCESS_NET_CONNECT_TCP); - LL_PORT(443, LANDLOCK_ACCESS_NET_CONNECT_TCP); + LL_PORT(80, LANDLOCK_ACCESS_NET_CONNECT_TCP_COMPAT); + LL_PORT(443, LANDLOCK_ACCESS_NET_CONNECT_TCP_COMPAT); } LL_END -- cgit v1.2.3 From bbce5e32caeb6ff86eabf08200db701151829884 Mon Sep 17 00:00:00 2001 From: shtrophic Date: Mon, 30 Dec 2024 11:18:08 +0100 Subject: use correct macros for compatibility --- sandbox.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/sandbox.c b/sandbox.c index b7c602e..f417e86 100644 --- a/sandbox.c +++ b/sandbox.c @@ -15,15 +15,15 @@ LL_BEGIN(sbox_enter_linux_, const char* basedir, const char *address, int smail) const unsigned long long rd = LANDLOCK_ACCESS_FS_READ_DIR, rf = LANDLOCK_ACCESS_FS_READ_FILE, - w = LANDLOCK_ACCESS_FS_WRITE_FILE | - LANDLOCK_ACCESS_FS_TRUNCATE, - c = LANDLOCK_ACCESS_FS_MAKE_DIR | - LANDLOCK_ACCESS_FS_MAKE_REG | - LANDLOCK_ACCESS_FS_TRUNCATE | - LANDLOCK_ACCESS_FS_MAKE_SYM | - LANDLOCK_ACCESS_FS_REMOVE_DIR | - LANDLOCK_ACCESS_FS_REMOVE_FILE | - LANDLOCK_ACCESS_FS_REFER, + w = LANDLOCK_ACCESS_FS_WRITE_FILE | + LANDLOCK_ACCESS_FS_TRUNCATE_COMPAT, + c = LANDLOCK_ACCESS_FS_MAKE_DIR | + LANDLOCK_ACCESS_FS_MAKE_REG | + LANDLOCK_ACCESS_FS_TRUNCATE_COMPAT | + LANDLOCK_ACCESS_FS_MAKE_SYM | + LANDLOCK_ACCESS_FS_REMOVE_DIR | + LANDLOCK_ACCESS_FS_REMOVE_FILE | + LANDLOCK_ACCESS_FS_REFER_COMPAT, s = LANDLOCK_ACCESS_FS_MAKE_SOCK, x = LANDLOCK_ACCESS_FS_EXECUTE; -- cgit v1.2.3 From a0ca57cc670c9c6dad633ba55a73d810ed61e5ce Mon Sep 17 00:00:00 2001 From: shtrophic Date: Mon, 30 Dec 2024 11:31:11 +0100 Subject: update landloc.h --- landloc.h | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/landloc.h b/landloc.h index 8995871..1e717c9 100644 --- a/landloc.h +++ b/landloc.h @@ -70,7 +70,9 @@ int main(void) { #include -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 13, 0) +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 13, 0) +# error "no landlock on kernels older than 5.13.0" +#endif #include #include @@ -224,10 +226,13 @@ int main(void) { #else -#define LL_PORT(p, rules) do { (void)p; (void)rules; } while (0) +#define LL_PORT(p, rules) do {\ + unsigned short __port = (p);\ + __u64 __rules = (rules);\ + (void)__port;\ + (void)__rules;\ +} while (0) #endif /* LL_HAVE_NET */ -#endif /* KERNEL_VERSION(5, 13, 0) */ - #endif /* __LANDLOC_H__ */ -- cgit v1.2.3