Merged Landlock feature

This commit is contained in:
Yves Rutschle 2023-12-09 14:13:07 +01:00
commit b65f1e8b26
5 changed files with 128 additions and 1 deletions

View File

@ -1,3 +1,7 @@
vNEXT:
Support for the Landlock LSM. After initial setup,
sslh gives up all local file access rights.
v2.0.1:
Fix resolve_on_forward setting, which would crash
sslh reliably.

View File

@ -9,6 +9,7 @@ USELIBCONFIG=1 # Use libconfig? (necessary to use configuration files)
USELIBEV=1 # Use libev?
USELIBWRAP?= # Use libwrap?
USELIBCAP= # Use libcap?
USELANDLOCK=1 # Use the landlock LSM?
USESYSTEMD= # Make use of systemd socket activation
USELIBBSD?= # Use libbsd (needed to update process name in `ps`)
COV_TEST= # Perform test coverage?
@ -35,7 +36,7 @@ CFLAGS +=-Wall -O2 -DLIBPCRE -g $(CFLAGS_COV) $(CFLAGS_SAN)
LIBS=-lm -lpcre2-8
OBJS=sslh-conf.o common.o log.o sslh-main.o probe.o tls.o argtable3.o collection.o gap.o tcp-probe.o
OBJS=sslh-conf.o common.o log.o sslh-main.o probe.o tls.o argtable3.o collection.o gap.o tcp-probe.o landlock.o
OBJS_A=libsslh.a
FORK_OBJS=sslh-fork.o $(OBJS_A)
SELECT_OBJS=processes.o udp-listener.o sslh-select.o hash.o tcp-listener.o $(OBJS_A)
@ -77,6 +78,12 @@ ifneq ($(strip $(USELIBEV)),)
CONDITIONAL_TARGETS+=sslh-ev
endif
ifneq ($(strip $(USELANDLOCK)),)
CPPFLAGS+=-DLANDLOCK
endif
all: sslh-fork sslh-select $(MAN) echosrv $(CONDITIONAL_TARGETS)
%.o: %.c %.h version.h

View File

@ -183,4 +183,8 @@ void start_shoveler(int);
void main_loop(struct listen_endpoint *listen_sockets, int num_addr_listen);
/* landlock.c */
void setup_landlock(void);
#endif

111
landlock.c Normal file
View File

@ -0,0 +1,111 @@
/*
* Setup a sandbox using the Landlock LSM, if available.
# Copyright (C) 2023 Yves Rutschle
#
# This program is free software; you can redistribute it
# and/or modify it under the terms of the GNU General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be
# useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more
# details.
#
# The full text for the General Public License is here:
# http://www.gnu.org/licenses/gpl.html
#
*/
#ifdef LANDLOCK
#define _GNU_SOURCE
#include <linux/landlock.h>
#include <sys/prctl.h>
#include <sys/syscall.h>
#include "log.h"
#ifndef landlock_create_ruleset
static inline int
landlock_create_ruleset(const struct landlock_ruleset_attr *const attr,
const size_t size, const __u32 flags)
{
return syscall(__NR_landlock_create_ruleset, attr, size, flags);
}
#endif
#ifndef landlock_add_rule
static inline int landlock_add_rule(const int ruleset_fd,
const enum landlock_rule_type rule_type,
const void *const rule_attr,
const __u32 flags)
{
return syscall(__NR_landlock_add_rule, ruleset_fd, rule_type, rule_attr,
flags);
}
#endif
#ifndef landlock_restrict_self
static inline int landlock_restrict_self(const int ruleset_fd,
const __u32 flags)
{
return syscall(__NR_landlock_restrict_self, ruleset_fd, flags);
}
#endif
void setup_landlock(void)
{
__u64 restrict_rules =
LANDLOCK_ACCESS_FS_EXECUTE |
LANDLOCK_ACCESS_FS_READ_FILE |
LANDLOCK_ACCESS_FS_READ_DIR |
LANDLOCK_ACCESS_FS_WRITE_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;
struct landlock_ruleset_attr ruleset_attr = {
.handled_access_fs = restrict_rules
};
/* ruleset_addr.handled_access_fs contains all rights that will be restricted
* unless explicitly added */
int ruleset_fd = landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
if (ruleset_fd < 0) {
print_message(msg_config_error, "Landlock: Failed to create a ruleset");
return;
}
/* No call to landlock_add_rule: we retain no rights whatsoever */
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
print_message(msg_config_error, "Landlock: Failed to restrict privileges");
return;
}
if (landlock_restrict_self(ruleset_fd, 0)) {
print_message(msg_config_error, "Landlock: Failed to enforce ruleset");
return;
}
close(ruleset_fd);
print_message(msg_config, "Landlock: all restricted\n");
}
#else
void setup_landlock(void)
{
return;
}
#endif

View File

@ -283,6 +283,7 @@ int main(int argc, char *argv[], char* envp[])
if (cfg.user || cfg.chroot)
drop_privileges(cfg.user, cfg.chroot);
setup_landlock();
printcaps();