core: block PTRACE_POKE{TEXT,DATA} when RestrictFileSystemAccess= is enabled

PTRACE_POKETEXT and PTRACE_POKEDATA use FOLL_FORCE to forcibly write
into a tracee's memory. That includes executable read-only pages. If we
restrict execution to trusted binaries PID 1 must enforce that it's
impossible to abuse this to get untrusted code execution. Note, that
usermodehelpers are not subject to PID 1's seccomp filters.

Install a ptrace seccomp filter from PID 1 if RestrictFileSystemAccess=
is requested. Every process it spawns will inherit it.

Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
This commit is contained in:
Christian Brauner
2026-08-31 23:33:40 +02:00
parent 179781353a
commit 4f4502ed23
3 changed files with 53 additions and 2 deletions
+38 -1
View File
@@ -13,6 +13,7 @@
#include "lsm-util.h"
#include "manager.h"
#include "memory-util.h"
#include "seccomp-util.h"
#include "serialize.h"
#include "string-table.h"
@@ -123,6 +124,26 @@ int bpf_restrict_fsaccess_check_prerequisites(void) {
return 0;
}
/* The seccomp filter survives execve() so ensure that we're not installing another filter. */
static int restrict_fsaccess_install_ptrace_filter(Manager *m) {
int r;
assert(m);
if (m->restrict_fsaccess_ptrace_filter)
return 0;
r = seccomp_restrict_ptrace();
if (r == -EOPNOTSUPP)
return log_error_errno(r, "bpf-restrict-fsaccess: seccomp support is not available, cannot block "
"ptrace() code injection.");
if (r < 0)
return log_error_errno(r, "bpf-restrict-fsaccess: Failed to install the ptrace() seccomp filter: %m");
m->restrict_fsaccess_ptrace_filter = true;
return 0;
}
static int get_root_s_dev(uint32_t *ret) {
struct stat st;
@@ -442,6 +463,10 @@ int bpf_restrict_fsaccess_setup(Manager *m) {
return r;
}
/* v261 serialized the link FDs without installing the filter. Enforcement is active already,
* so only complain. */
(void) restrict_fsaccess_install_ptrace_filter(m);
return 0;
}
@@ -449,6 +474,10 @@ int bpf_restrict_fsaccess_setup(Manager *m) {
if (r < 0)
return r;
r = restrict_fsaccess_install_ptrace_filter(m);
if (r < 0)
return r;
r = bpf_restrict_fsaccess_prepare(&obj);
if (r < 0)
return r;
@@ -548,7 +577,15 @@ int bpf_restrict_fsaccess_serialize(Manager *m, FILE *f, FDSet *fds) {
assert(f);
assert(fds);
if (!MANAGER_IS_SYSTEM(m) || m->restrict_filesystem_access <= RESTRICT_FILESYSTEM_ACCESS_NO)
if (!MANAGER_IS_SYSTEM(m))
return 0;
/* Process state, not policy state: the filter outlives the setting being turned off. */
r = serialize_bool_elide(f, "restrict-fsaccess-ptrace-filter", m->restrict_fsaccess_ptrace_filter);
if (r < 0)
return r;
if (m->restrict_filesystem_access <= RESTRICT_FILESYSTEM_ACCESS_NO)
return 0;
FOREACH_ELEMENT(fd, m->restrict_fsaccess_link_fds) {
+12 -1
View File
@@ -519,7 +519,7 @@ static void manager_deserialize_gid_refs_one(Manager *m, const char *value) {
static void deserialize_restrict_fsaccess(Manager *m, const char *l, FDSet *fds) {
const char *val;
int fd;
int fd, r;
FOREACH_ELEMENT(name, restrict_fsaccess_link_names) {
val = startswith(l, *name);
@@ -537,6 +537,17 @@ static void deserialize_restrict_fsaccess(Manager *m, const char *l, FDSet *fds)
return;
}
val = startswith(l, "restrict-fsaccess-ptrace-filter=");
if (val) {
r = parse_boolean(val);
if (r < 0)
log_warning_errno(r, "bpf-restrict-fsaccess: Failed to parse ptrace filter state '%s', "
"ignoring: %m", val);
else
m->restrict_fsaccess_ptrace_filter = r;
return;
}
val = startswith(l, "restrict-fsaccess-bss-map=");
if (!val)
return;
+3
View File
@@ -514,6 +514,9 @@ typedef struct Manager {
int restrict_fsaccess_link_fds[_RESTRICT_FILESYSTEM_ACCESS_LINK_MAX];
int restrict_fsaccess_bss_map_fd;
/* Whether the ptrace seccomp filter is installed in this process; it survives execve() */
bool restrict_fsaccess_ptrace_filter;
/* Allow users to configure a rate limit for Reload()/Reexecute() operations */
RateLimit reload_reexec_ratelimit;
/* Dump*() are slow, so always rate limit them to 10 per 10 minutes */