Begin landlock support
This commit is contained in:
parent
7e2d4139cb
commit
bb02e40101
160
qssb.h
160
qssb.h
@ -50,6 +50,9 @@
|
|||||||
#endif
|
#endif
|
||||||
#if HAVE_LANDLOCK == 1
|
#if HAVE_LANDLOCK == 1
|
||||||
#include <linux/landlock.h>
|
#include <linux/landlock.h>
|
||||||
|
#if LANDLOCK_CREATE_RULESET_VERSION != (1U << 0)
|
||||||
|
#error "This landlock ABI version is not supported by qssb (yet)"
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//TODO: stolen from kernel samples/seccomp, GPLv2...?
|
//TODO: stolen from kernel samples/seccomp, GPLv2...?
|
||||||
@ -96,8 +99,36 @@
|
|||||||
#define QSSB_FS_ALLOW_MAKE_FIFO (1 << 13)
|
#define QSSB_FS_ALLOW_MAKE_FIFO (1 << 13)
|
||||||
#define QSSB_FS_ALLOW_MAKE_BLOCK (1 << 14)
|
#define QSSB_FS_ALLOW_MAKE_BLOCK (1 << 14)
|
||||||
#define QSSB_FS_ALLOW_MAKE_SYM (1 << 15)
|
#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
|
#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
|
||||||
@ -146,7 +177,6 @@ struct qssb_policy
|
|||||||
struct qssb_path_policy *path_policies;
|
struct qssb_path_policy *path_policies;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* 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 */
|
||||||
@ -508,9 +538,117 @@ static int seccomp_enable_whitelist(int *syscalls)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if HAVE_LANDLOCK == 1
|
#if HAVE_LANDLOCK == 1
|
||||||
static int enable_landlock_policies(struct qssb_path_policy *policies)
|
static unsigned int qssb_flags_to_landlock(unsigned int flags)
|
||||||
{
|
{
|
||||||
return 0;
|
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
|
#endif
|
||||||
|
|
||||||
@ -620,11 +758,13 @@ int qssb_enable_policy(struct qssb_policy *policy)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if HAVE_LANDLOCK == 1
|
#if HAVE_LANDLOCK == 1
|
||||||
|
int landlock_ruleset_fd = -1;
|
||||||
if(policy->path_policies != NULL)
|
if(policy->path_policies != NULL)
|
||||||
{
|
{
|
||||||
if(enable_landlock_policies(policy->path_policies) < 0)
|
landlock_ruleset_fd = landlock_prepare_ruleset(policy->path_policies);
|
||||||
|
if(landlock_ruleset_fd < 0)
|
||||||
{
|
{
|
||||||
QSSB_LOG_ERROR("enable_landlock_policies: Failed to enable landlock policies\n");
|
QSSB_LOG_ERROR("landlock_prepare_ruleset: Failed to prepare landlock ruleset: %s\n", strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -668,6 +808,16 @@ 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…
Reference in New Issue
Block a user