Compare commits
No commits in common. "946492c28eee759fc331c9f73d9c705c65da321e" and "9df2e9ee905ac33bebf6df1e50c626f92a851c1a" have entirely different histories.
946492c28e
...
9df2e9ee90
354
qssb.h
354
qssb.h
@ -1,19 +1,3 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2021 Albert S. <mail at quitesimple dot 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef QSSB_H
|
#ifndef QSSB_H
|
||||||
#define QSSB_H
|
#define QSSB_H
|
||||||
|
|
||||||
@ -29,7 +13,6 @@
|
|||||||
#include <sys/mount.h>
|
#include <sys/mount.h>
|
||||||
#include <sys/prctl.h>
|
#include <sys/prctl.h>
|
||||||
#include <sys/random.h>
|
#include <sys/random.h>
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@ -37,25 +20,11 @@
|
|||||||
#include <linux/limits.h>
|
#include <linux/limits.h>
|
||||||
#include <linux/filter.h>
|
#include <linux/filter.h>
|
||||||
#include <linux/seccomp.h>
|
#include <linux/seccomp.h>
|
||||||
#include <linux/version.h>
|
|
||||||
#include <sys/capability.h>
|
#include <sys/capability.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <asm/unistd.h>
|
#include <asm/unistd.h>
|
||||||
|
|
||||||
#ifndef HAVE_LANDLOCK
|
|
||||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,13,0)
|
|
||||||
/* TODO: Hopefully a fair assumption. But we need to runtime checks */
|
|
||||||
#define HAVE_LANDLOCK = 1
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#if HAVE_LANDLOCK == 1
|
|
||||||
#include <linux/landlock.h>
|
|
||||||
#if LANDLOCK_CREATE_RULESET_VERSION != (1U << 0)
|
|
||||||
#error "This landlock ABI version is not supported by qssb (yet)"
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//TODO: stolen from kernel samples/seccomp, GPLv2...?
|
//TODO: stolen from kernel samples/seccomp, GPLv2...?
|
||||||
#define ALLOW \
|
#define ALLOW \
|
||||||
BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW)
|
BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW)
|
||||||
@ -82,55 +51,17 @@
|
|||||||
|
|
||||||
#define QSSB_SYS(x) (__NR_##x)
|
#define QSSB_SYS(x) (__NR_##x)
|
||||||
|
|
||||||
#define QSSB_FS_ALLOW_READ 1<<0
|
//TODO: implement
|
||||||
#define QSSB_FS_ALLOW_WRITE (1<<1)
|
#define QSSB_MOUNT_ALLOW_NOTHING 0 //explicit rule
|
||||||
#define QSSB_FS_ALLOW_EXEC 1<<2
|
|
||||||
#define QSSB_FS_ALLOW_DEV 1<<3
|
#define QSSB_MOUNT_ALLOW_READ 1<<0
|
||||||
#define QSSB_FS_ALLOW_SETUID 1<<4
|
#define QSSB_MOUNT_ALLOW_WRITE (1<<1) | QSSB_MOUNT_ALLOW_READ
|
||||||
|
#define QSSB_MOUNT_ALLOW_EXEC 1<<2
|
||||||
|
#define QSSB_MOUNT_ALLOW_DEV 1<<3
|
||||||
|
#define QSSB_MOUNT_ALLOW_SETUID 1<<4
|
||||||
//don't mount recursive
|
//don't mount recursive
|
||||||
#define QSSB_MOUNT_NOT_REC 1<<5
|
#define QSSB_MOUNT_NOT_REC 1<<5
|
||||||
|
|
||||||
#if HAVE_LANDLOCK == 1
|
|
||||||
#define QSSB_FS_ALLOW_REMOVE_DIR (1 << 7)
|
|
||||||
#define QSSB_FS_ALLOW_REMOVE_FILE (1 << 8)
|
|
||||||
#define QSSB_FS_ALLOW_MAKE_CHAR (1 << 9)
|
|
||||||
#define QSSB_FS_ALLOW_MAKE_DIR (1 << 10)
|
|
||||||
#define QSSB_FS_ALLOW_MAKE_REG (1 << 11)
|
|
||||||
#define QSSB_FS_ALLOW_MAKE_SOCK (1 << 12)
|
|
||||||
#define QSSB_FS_ALLOW_MAKE_FIFO (1 << 13)
|
|
||||||
#define QSSB_FS_ALLOW_MAKE_BLOCK (1 << 14)
|
|
||||||
#define QSSB_FS_ALLOW_MAKE_SYM (1 << 15)
|
|
||||||
#define QSSB_FS_ALLOW_WRITE_FILE (1 << 16)
|
|
||||||
#define QSSB_FS_ALLOW_READ_DIR (1 << 17)
|
|
||||||
#define QSSB_FS_ALLOW_REMOVE (1 << 18)
|
|
||||||
|
|
||||||
#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
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Most exploits have more need for those syscalls than the
|
/* Most exploits have more need for those syscalls than the
|
||||||
* exploited programs. In cases they are needed, this list should be
|
* exploited programs. In cases they are needed, this list should be
|
||||||
@ -154,8 +85,8 @@ static int default_blacklisted_syscals[] = {
|
|||||||
|
|
||||||
struct qssb_path_policy
|
struct qssb_path_policy
|
||||||
{
|
{
|
||||||
const char *path;
|
const char *mountpoint;
|
||||||
unsigned int policy;
|
int policy;
|
||||||
struct qssb_path_policy *next;
|
struct qssb_path_policy *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -169,19 +100,14 @@ struct qssb_policy
|
|||||||
int no_new_privs;
|
int no_new_privs;
|
||||||
int namespace_options;
|
int namespace_options;
|
||||||
int syscall_default_policy;
|
int syscall_default_policy;
|
||||||
/* Bind mounts all paths in path_policies into the chroot and applies
|
|
||||||
non-landlock policies */
|
|
||||||
int mount_path_policies_to_chroot;
|
|
||||||
int *blacklisted_syscalls;
|
int *blacklisted_syscalls;
|
||||||
int *allowed_syscalls;
|
int *allowed_syscalls;
|
||||||
char chroot_target_path[PATH_MAX];
|
char chroot_target_path[PATH_MAX];
|
||||||
const char *chdir_path;
|
const char *chdir_path;
|
||||||
|
|
||||||
/* Do not manually add policies here, use qssb_append_path_polic*() */
|
|
||||||
struct qssb_path_policy *path_policies;
|
struct qssb_path_policy *path_policies;
|
||||||
struct qssb_path_policy **path_policies_tail;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Creates the default policy
|
/* Creates the default policy
|
||||||
* Must be freed using qssb_free_policy
|
* Must be freed using qssb_free_policy
|
||||||
* @returns: default policy */
|
* @returns: default policy */
|
||||||
@ -194,46 +120,11 @@ struct qssb_policy *qssb_init_policy()
|
|||||||
result->no_new_privs = 1;
|
result->no_new_privs = 1;
|
||||||
result->namespace_options = QSSB_UNSHARE_MOUNT | QSSB_UNSHARE_USER;
|
result->namespace_options = QSSB_UNSHARE_MOUNT | QSSB_UNSHARE_USER;
|
||||||
result->chdir_path = NULL;
|
result->chdir_path = NULL;
|
||||||
result->mount_path_policies_to_chroot = 0;
|
|
||||||
result->chroot_target_path[0] = '\0';
|
result->chroot_target_path[0] = '\0';
|
||||||
result->path_policies = NULL;
|
result->path_policies = NULL;
|
||||||
result->path_policies_tail = &(result->path_policies);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int qssb_append_path_policies(struct qssb_policy *qssb_policy, unsigned int path_policy, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
const char *path;
|
|
||||||
va_start(args, path_policy);
|
|
||||||
|
|
||||||
path = va_arg(args, char*);
|
|
||||||
while(path != NULL)
|
|
||||||
{
|
|
||||||
struct qssb_path_policy *newpolicy = calloc(1, sizeof(struct qssb_path_policy));
|
|
||||||
if(newpolicy == NULL)
|
|
||||||
{
|
|
||||||
QSSB_LOG_ERROR("Failed to allocate memory for path policy\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
newpolicy->path = path;
|
|
||||||
newpolicy->policy = path_policy;
|
|
||||||
newpolicy->next = NULL;
|
|
||||||
|
|
||||||
*(qssb_policy->path_policies_tail) = newpolicy;
|
|
||||||
qssb_policy->path_policies_tail = &(newpolicy->next);
|
|
||||||
path = va_arg(args, char*);
|
|
||||||
}
|
|
||||||
|
|
||||||
va_end(args);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int qssb_append_path_policy(struct qssb_policy *qssb_policy, unsigned int path_policy, const char *path)
|
|
||||||
{
|
|
||||||
return qssb_append_path_policies(qssb_policy, path_policy, path, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fills buffer with random characters a-z.
|
* Fills buffer with random characters a-z.
|
||||||
@ -314,32 +205,34 @@ static int mkdir_structure(const char *p, mode_t mode)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* @returns: argument for mount(2) flags */
|
/* @returns: argument for mount(2) flags */
|
||||||
static int get_policy_mount_flags(struct qssb_path_policy *policy)
|
static int get_policy_mount_flags(struct qssb_path_policy *policy)
|
||||||
{
|
{
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
||||||
if( (policy->policy & QSSB_FS_ALLOW_DEV) == 0)
|
if( (policy->policy & QSSB_MOUNT_ALLOW_DEV) == 0)
|
||||||
{
|
{
|
||||||
result |= MS_NODEV;
|
result |= MS_NODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( (policy->policy & QSSB_FS_ALLOW_EXEC) == 0)
|
if( (policy->policy & QSSB_MOUNT_ALLOW_EXEC) == 0)
|
||||||
{
|
{
|
||||||
result |= MS_NOEXEC;
|
result |= MS_NOEXEC;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( (policy->policy & QSSB_FS_ALLOW_SETUID) == 0)
|
if( (policy->policy & QSSB_MOUNT_ALLOW_SETUID) == 0)
|
||||||
{
|
{
|
||||||
result |= MS_NOSUID;
|
result |= MS_NOSUID;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( (policy->policy & QSSB_FS_ALLOW_WRITE) == 0)
|
if( ((policy->policy) & (QSSB_MOUNT_ALLOW_WRITE)) == QSSB_MOUNT_ALLOW_READ)
|
||||||
{
|
{
|
||||||
result |= MS_RDONLY;
|
result |= MS_RDONLY;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( (policy->policy & QSSB_MOUNT_NOT_REC) == 0)
|
if( !(policy->policy & QSSB_MOUNT_NOT_REC))
|
||||||
{
|
{
|
||||||
result |= MS_REC;
|
result |= MS_REC;
|
||||||
}
|
}
|
||||||
@ -356,7 +249,7 @@ static int mount_to_chroot(const char *chroot_target_path, struct qssb_path_poli
|
|||||||
{
|
{
|
||||||
|
|
||||||
char path_inside_chroot[PATH_MAX];
|
char path_inside_chroot[PATH_MAX];
|
||||||
int written = snprintf(path_inside_chroot, sizeof(path_inside_chroot), "%s/%s", chroot_target_path, path_policy->path);
|
int written = snprintf(path_inside_chroot, sizeof(path_inside_chroot), "%s/%s", chroot_target_path, path_policy->mountpoint);
|
||||||
if(written < 0)
|
if(written < 0)
|
||||||
{
|
{
|
||||||
QSSB_LOG_ERROR("qssb: mount_to_chroot: Error during path concatination\n");
|
QSSB_LOG_ERROR("qssb: mount_to_chroot: Error during path concatination\n");
|
||||||
@ -380,12 +273,12 @@ static int mount_to_chroot(const char *chroot_target_path, struct qssb_path_poli
|
|||||||
mount_flags |= MS_BIND;
|
mount_flags |= MS_BIND;
|
||||||
|
|
||||||
|
|
||||||
if(path_policy->policy & QSSB_FS_ALLOW_READ || path_policy->policy & QSSB_FS_ALLOW_WRITE)
|
if(path_policy->policy & QSSB_MOUNT_ALLOW_READ)
|
||||||
{
|
{
|
||||||
ret = mount(path_policy->path, path_inside_chroot, NULL, mount_flags, NULL);
|
ret = mount(path_policy->mountpoint, path_inside_chroot, NULL, mount_flags, NULL);
|
||||||
if(ret < 0 )
|
if(ret < 0 )
|
||||||
{
|
{
|
||||||
QSSB_LOG_ERROR("Error: Failed to mount %s to %s: %s\n", path_policy->path, path_inside_chroot, strerror(errno));
|
QSSB_LOG_ERROR("Error: Failed to mount %s to %s: %s\n", path_policy->mountpoint, path_inside_chroot, strerror(errno));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -415,13 +308,6 @@ int qssb_end_policy(struct qssb_policy *ctxt)
|
|||||||
*/
|
*/
|
||||||
void qssb_free_policy(struct qssb_policy *ctxt)
|
void qssb_free_policy(struct qssb_policy *ctxt)
|
||||||
{
|
{
|
||||||
struct qssb_path_policy *current = ctxt->path_policies;
|
|
||||||
while(current)
|
|
||||||
{
|
|
||||||
struct qssb_path_policy *tmp = current;
|
|
||||||
current = current->next;
|
|
||||||
free(tmp);
|
|
||||||
}
|
|
||||||
free(ctxt);
|
free(ctxt);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -581,164 +467,6 @@ static int seccomp_enable_whitelist(int *syscalls)
|
|||||||
return seccomp_enable(syscalls, SECCOMP_RET_ALLOW, SECCOMP_RET_KILL);
|
return seccomp_enable(syscalls, SECCOMP_RET_ALLOW, SECCOMP_RET_KILL);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if HAVE_LANDLOCK == 1
|
|
||||||
static unsigned int qssb_flags_to_landlock(unsigned int flags)
|
|
||||||
{
|
|
||||||
unsigned int result = 0;
|
|
||||||
if(flags & QSSB_FS_ALLOW_DEV)
|
|
||||||
{
|
|
||||||
result |= LANDLOCK_ACCESS_FS_MAKE_BLOCK;
|
|
||||||
result |= LANDLOCK_ACCESS_FS_MAKE_CHAR;
|
|
||||||
}
|
|
||||||
if(flags & QSSB_FS_ALLOW_MAKE_BLOCK)
|
|
||||||
{
|
|
||||||
result |= LANDLOCK_ACCESS_FS_MAKE_BLOCK;
|
|
||||||
}
|
|
||||||
if(flags & QSSB_FS_ALLOW_MAKE_CHAR)
|
|
||||||
{
|
|
||||||
result |= LANDLOCK_ACCESS_FS_MAKE_CHAR;
|
|
||||||
}
|
|
||||||
if(flags & QSSB_FS_ALLOW_MAKE_DIR)
|
|
||||||
{
|
|
||||||
result |= LANDLOCK_ACCESS_FS_MAKE_DIR;
|
|
||||||
}
|
|
||||||
if(flags & QSSB_FS_ALLOW_MAKE_FIFO)
|
|
||||||
{
|
|
||||||
result |= LANDLOCK_ACCESS_FS_MAKE_FIFO;
|
|
||||||
}
|
|
||||||
if(flags & QSSB_FS_ALLOW_MAKE_REG)
|
|
||||||
{
|
|
||||||
result |= LANDLOCK_ACCESS_FS_MAKE_REG;
|
|
||||||
}
|
|
||||||
if(flags & QSSB_FS_ALLOW_MAKE_SOCK)
|
|
||||||
{
|
|
||||||
result |= LANDLOCK_ACCESS_FS_MAKE_SOCK;
|
|
||||||
}
|
|
||||||
if(flags & QSSB_FS_ALLOW_MAKE_SYM)
|
|
||||||
{
|
|
||||||
result |= LANDLOCK_ACCESS_FS_MAKE_SYM;
|
|
||||||
}
|
|
||||||
if(flags & QSSB_FS_ALLOW_READ)
|
|
||||||
{
|
|
||||||
result |= LANDLOCK_ACCESS_FS_READ_FILE;
|
|
||||||
result |= LANDLOCK_ACCESS_FS_READ_DIR;
|
|
||||||
}
|
|
||||||
if(flags & QSSB_FS_ALLOW_REMOVE)
|
|
||||||
{
|
|
||||||
result |= LANDLOCK_ACCESS_FS_REMOVE_DIR;
|
|
||||||
result |= LANDLOCK_ACCESS_FS_REMOVE_FILE;
|
|
||||||
}
|
|
||||||
if(flags & QSSB_FS_ALLOW_REMOVE_DIR)
|
|
||||||
{
|
|
||||||
result |= LANDLOCK_ACCESS_FS_REMOVE_DIR;
|
|
||||||
}
|
|
||||||
if(flags & QSSB_FS_ALLOW_REMOVE_FILE)
|
|
||||||
{
|
|
||||||
result |= LANDLOCK_ACCESS_FS_REMOVE_FILE;
|
|
||||||
}
|
|
||||||
if(flags & QSSB_FS_ALLOW_EXEC)
|
|
||||||
{
|
|
||||||
result |= LANDLOCK_ACCESS_FS_EXECUTE;
|
|
||||||
}
|
|
||||||
if(flags & QSSB_FS_ALLOW_WRITE)
|
|
||||||
{
|
|
||||||
result |= LANDLOCK_ACCESS_FS_MAKE_REG;
|
|
||||||
result |= LANDLOCK_ACCESS_FS_WRITE_FILE;
|
|
||||||
}
|
|
||||||
if(flags & QSSB_FS_ALLOW_WRITE_FILE)
|
|
||||||
{
|
|
||||||
result |= LANDLOCK_ACCESS_FS_WRITE_FILE;
|
|
||||||
}
|
|
||||||
if(flags & QSSB_FS_ALLOW_READ_DIR)
|
|
||||||
{
|
|
||||||
result |= LANDLOCK_ACCESS_FS_READ_DIR;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int landlock_prepare_ruleset(struct qssb_path_policy *policies)
|
|
||||||
{
|
|
||||||
int ruleset_fd = -1;
|
|
||||||
struct landlock_ruleset_attr ruleset_attr;
|
|
||||||
/* We here want the maximum possible ruleset, so set the var to the max possible bitmask.
|
|
||||||
Stolen/Adapted from: [linux src]/security/landlock/limits.h
|
|
||||||
*/
|
|
||||||
ruleset_attr.handled_access_fs = ((LANDLOCK_ACCESS_FS_MAKE_SYM << 1) - 1);
|
|
||||||
|
|
||||||
ruleset_fd = landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
|
|
||||||
if (ruleset_fd < 0)
|
|
||||||
{
|
|
||||||
QSSB_LOG_ERROR("Failed to create landlock ruleset");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
struct qssb_path_policy *policy = policies;
|
|
||||||
while(policy != NULL)
|
|
||||||
{
|
|
||||||
struct landlock_path_beneath_attr path_beneath;
|
|
||||||
path_beneath.parent_fd = open(policy->path, O_PATH | O_CLOEXEC);
|
|
||||||
if(path_beneath.parent_fd < 0)
|
|
||||||
{
|
|
||||||
QSSB_LOG_ERROR("Failed to open policy path %s while preparing landlock ruleset\n", policy->path);
|
|
||||||
close(ruleset_fd);
|
|
||||||
return path_beneath.parent_fd;
|
|
||||||
}
|
|
||||||
path_beneath.allowed_access = qssb_flags_to_landlock(policy->policy);
|
|
||||||
int ret = landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, &path_beneath, 0);
|
|
||||||
if(ret)
|
|
||||||
{
|
|
||||||
QSSB_LOG_ERROR("Failed to update ruleset while processsing policy path %s\n", policy->path);
|
|
||||||
close(ruleset_fd);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
policy = policy->next;
|
|
||||||
}
|
|
||||||
return ruleset_fd;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/* Checks for illogical or dangerous combinations */
|
|
||||||
static int check_policy_sanity(struct qssb_policy *policy)
|
|
||||||
{
|
|
||||||
if(policy->blacklisted_syscalls != NULL && policy->allowed_syscalls != NULL)
|
|
||||||
{
|
|
||||||
QSSB_LOG_ERROR("Error: Cannot mix blacklisted and whitelisted systemcalls\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(policy->mount_path_policies_to_chroot == 1)
|
|
||||||
{
|
|
||||||
if(policy->path_policies == NULL)
|
|
||||||
{
|
|
||||||
QSSB_LOG_ERROR("Cannot mount path policies to chroot if non are given\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if(!(policy->namespace_options & QSSB_UNSHARE_MOUNT))
|
|
||||||
{
|
|
||||||
QSSB_LOG_ERROR("mount_path_policies_to_chroot = 1 requires unsharing mount namespace\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(policy->no_new_privs != 1)
|
|
||||||
{
|
|
||||||
if(policy->blacklisted_syscalls != NULL || policy->allowed_syscalls != NULL)
|
|
||||||
{
|
|
||||||
QSSB_LOG_ERROR("no_new_privs = 1 is required for seccomp filtering!\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(policy->path_policies != NULL && policy->mount_path_policies_to_chroot != 1)
|
|
||||||
{
|
|
||||||
#if HAVE_LANDLOCK != 1
|
|
||||||
QSSB_LOG_ERROR("Path policies cannot be enforced! System needs landlock support or set mount_path_policies_to_chroot = 1\n");
|
|
||||||
return -1;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Enables the specified qssb_policy.
|
/* Enables the specified qssb_policy.
|
||||||
*
|
*
|
||||||
* The calling process is supposed *TO BE WRITTEN* if
|
* The calling process is supposed *TO BE WRITTEN* if
|
||||||
@ -747,9 +475,9 @@ static int check_policy_sanity(struct qssb_policy *policy)
|
|||||||
*/
|
*/
|
||||||
int qssb_enable_policy(struct qssb_policy *policy)
|
int qssb_enable_policy(struct qssb_policy *policy)
|
||||||
{
|
{
|
||||||
if(check_policy_sanity(policy) != 0)
|
if(policy->blacklisted_syscalls != NULL && policy->allowed_syscalls != NULL)
|
||||||
{
|
{
|
||||||
QSSB_LOG_ERROR("Error: Policy sanity check failed. Cannot apply policy!\n");
|
QSSB_LOG_ERROR("Error: Cannot mix blacklisted and whitelisted systemcalls\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -759,7 +487,7 @@ int qssb_enable_policy(struct qssb_policy *policy)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(policy->mount_path_policies_to_chroot && policy->path_policies != NULL)
|
if(policy->path_policies != NULL)
|
||||||
{
|
{
|
||||||
if(*policy->chroot_target_path == '\0')
|
if(*policy->chroot_target_path == '\0')
|
||||||
{
|
{
|
||||||
@ -787,37 +515,21 @@ int qssb_enable_policy(struct qssb_policy *policy)
|
|||||||
|
|
||||||
if(mount_to_chroot(policy->chroot_target_path, policy->path_policies) < 0)
|
if(mount_to_chroot(policy->chroot_target_path, policy->path_policies) < 0)
|
||||||
{
|
{
|
||||||
QSSB_LOG_ERROR("mount_to_chroot: bind mounting of path policies failed\n");
|
QSSB_LOG_ERROR("mount_to_chroot: setup of path policies failed\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if(*policy->chroot_target_path != '\0')
|
|
||||||
{
|
|
||||||
if(chroot(policy->chroot_target_path) < 0)
|
if(chroot(policy->chroot_target_path) < 0)
|
||||||
{
|
{
|
||||||
QSSB_LOG_ERROR("chroot: failed to enter %s\n", policy->chroot_target_path);
|
QSSB_LOG_ERROR("chroot: failed to enter %s\n", policy->chroot_target_path);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#if HAVE_LANDLOCK == 1
|
if(policy->chdir_path == NULL)
|
||||||
int landlock_ruleset_fd = -1;
|
|
||||||
if(policy->path_policies != NULL)
|
|
||||||
{
|
|
||||||
landlock_ruleset_fd = landlock_prepare_ruleset(policy->path_policies);
|
|
||||||
if(landlock_ruleset_fd < 0)
|
|
||||||
{
|
{
|
||||||
QSSB_LOG_ERROR("landlock_prepare_ruleset: Failed to prepare landlock ruleset: %s\n", strerror(errno));
|
policy->chdir_path = "/";
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
if(policy->chdir_path == NULL)
|
|
||||||
{
|
|
||||||
policy->chdir_path = "/";
|
|
||||||
}
|
|
||||||
|
|
||||||
if(policy->chdir_path != NULL && chdir(policy->chdir_path) < 0)
|
if(policy->chdir_path != NULL && chdir(policy->chdir_path) < 0)
|
||||||
{
|
{
|
||||||
@ -852,16 +564,6 @@ int qssb_enable_policy(struct qssb_policy *policy)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if HAVE_LANDLOCK == 1
|
|
||||||
if (policy->path_policies != NULL && landlock_restrict_self(landlock_ruleset_fd, 0) != 0)
|
|
||||||
{
|
|
||||||
perror("Failed to enforce ruleset");
|
|
||||||
close(landlock_ruleset_fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
close(landlock_ruleset_fd);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if(policy->allowed_syscalls != NULL)
|
if(policy->allowed_syscalls != NULL)
|
||||||
{
|
{
|
||||||
if(seccomp_enable_whitelist(policy->allowed_syscalls) <0)
|
if(seccomp_enable_whitelist(policy->allowed_syscalls) <0)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user