Merge pull request #15332 from keszybz/coredump-filter

CoredumpFilter=
This commit is contained in:
Lennart Poettering 2020-04-09 17:15:26 +02:00 committed by GitHub
commit f58921bde3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 396 additions and 5 deletions

View File

@ -114,6 +114,7 @@ All execution-related settings are available for transient units.
✓ SupplementaryGroups=
✓ Nice=
✓ OOMScoreAdjust=
✓ CoredumpFilter=
✓ IOSchedulingClass=
✓ IOSchedulingPriority=
✓ CPUSchedulingPolicy=

View File

@ -656,6 +656,32 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
to 0022.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>CoredumpFilter=</varname></term>
<listitem><para>Controls which types of memory mappings will be saved if the process dumps core
(using the <filename>/proc/<replaceable>pid</replaceable>/coredump_filter</filename> file). Takes a
whitespace-separated combination of mapping type names or numbers (with the default base 16). Mapping
type names are <constant>private-anonymous</constant>, <constant>shared-anonymous</constant>,
<constant>private-file-backed</constant>, <constant>shared-file-backed</constant>,
<constant>elf-headers</constant>, <constant>private-huge</constant>,
<constant>shared-huge</constant>, <constant>private-dax</constant>, <constant>shared-dax</constant>,
and the special values <constant>all</constant> (all types) and <constant>default</constant> (the
kernel default of <literal><constant>private-anonymous</constant>
<constant>shared-anonymous</constant> <constant>elf-headers</constant>
<constant>private-huge</constant></literal>). See
<citerefentry><refentrytitle>core</refentrytitle><manvolnum>5</manvolnum></citerefentry> for the
meaning of the mapping types. When specified multiple times, all specified masks are ORed. When not
set, or if the empty value is assigned, the inherited value is not changed.</para>
<example>
<title>Add DAX pages to the dump filter</title>
<programlisting>CoredumpFilter=default private-dax shared-dax</programlisting>
</example>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>KeyringMode=</varname></term>

View File

@ -395,7 +395,7 @@ int safe_atoi(const char *s, int *ret_i) {
return 0;
}
int safe_atollu(const char *s, long long unsigned *ret_llu) {
int safe_atollu_full(const char *s, unsigned base, long long unsigned *ret_llu) {
char *x = NULL;
unsigned long long l;
@ -404,7 +404,7 @@ int safe_atollu(const char *s, long long unsigned *ret_llu) {
s += strspn(s, WHITESPACE);
errno = 0;
l = strtoull(s, &x, 0);
l = strtoull(s, &x, base);
if (errno > 0)
return -errno;
if (!x || x == s || *x != 0)

View File

@ -28,7 +28,6 @@ static inline int safe_atou(const char *s, unsigned *ret_u) {
}
int safe_atoi(const char *s, int *ret_i);
int safe_atollu(const char *s, unsigned long long *ret_u);
int safe_atolli(const char *s, long long int *ret_i);
int safe_atou8(const char *s, uint8_t *ret);
@ -59,6 +58,12 @@ static inline int safe_atoi32(const char *s, int32_t *ret_i) {
return safe_atoi(s, (int*) ret_i);
}
int safe_atollu_full(const char *s, unsigned base, long long unsigned *ret_llu);
static inline int safe_atollu(const char *s, long long unsigned *ret_llu) {
return safe_atollu_full(s, 0, ret_llu);
}
static inline int safe_atou64(const char *s, uint64_t *ret_u) {
assert_cc(sizeof(uint64_t) == sizeof(unsigned long long));
return safe_atollu(s, (unsigned long long*) ret_u);
@ -69,6 +74,11 @@ static inline int safe_atoi64(const char *s, int64_t *ret_i) {
return safe_atolli(s, (long long int*) ret_i);
}
static inline int safe_atoux64(const char *s, uint64_t *ret) {
assert_cc(sizeof(int64_t) == sizeof(long long unsigned));
return safe_atollu_full(s, 16, (long long unsigned*) ret);
}
#if LONG_MAX == INT_MAX
static inline int safe_atolu(const char *s, unsigned long *ret_u) {
assert_cc(sizeof(unsigned long) == sizeof(unsigned));

View File

@ -102,6 +102,7 @@ static int property_get_oom_score_adjust(
ExecContext *c = userdata;
int32_t n;
int r;
assert(bus);
assert(reply);
@ -113,13 +114,55 @@ static int property_get_oom_score_adjust(
_cleanup_free_ char *t = NULL;
n = 0;
if (read_one_line_file("/proc/self/oom_score_adj", &t) >= 0)
safe_atoi32(t, &n);
r = read_one_line_file("/proc/self/oom_score_adj", &t);
if (r < 0)
log_debug_errno(r, "Failed to read /proc/self/oom_score_adj, ignoring: %m");
else {
r = safe_atoi32(t, &n);
if (r < 0)
log_debug_errno(r, "Failed to parse \"%s\" from /proc/self/oom_score_adj, ignoring: %m", t);
}
}
return sd_bus_message_append(reply, "i", n);
}
static int property_get_coredump_filter(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error) {
ExecContext *c = userdata;
uint64_t n;
int r;
assert(bus);
assert(reply);
assert(c);
if (c->coredump_filter_set)
n = c->coredump_filter;
else {
_cleanup_free_ char *t = NULL;
n = COREDUMP_FILTER_MASK_DEFAULT;
r = read_one_line_file("/proc/self/coredump_filter", &t);
if (r < 0)
log_debug_errno(r, "Failed to read /proc/self/coredump_filter, ignoring: %m");
else {
r = safe_atoux64(t, &n);
if (r < 0)
log_debug_errno(r, "Failed to parse \"%s\" from /proc/self/coredump_filter, ignoring: %m", t);
}
}
return sd_bus_message_append(reply, "t", n);
}
static int property_get_nice(
sd_bus *bus,
const char *path,
@ -747,6 +790,7 @@ const sd_bus_vtable bus_exec_vtable[] = {
SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(ExecContext, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RootImage", "s", NULL, offsetof(ExecContext, root_image), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("OOMScoreAdjust", "i", property_get_oom_score_adjust, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("CoredumpFilter", "t", property_get_coredump_filter, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Nice", "i", property_get_nice, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("IOSchedulingClass", "i", property_get_ioprio_class, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("IOSchedulingPriority", "i", property_get_ioprio_priority, 0, SD_BUS_VTABLE_PROPERTY_CONST),
@ -2190,6 +2234,21 @@ int bus_exec_context_set_transient_property(
return 1;
} else if (streq(name, "CoredumpFilter")) {
uint64_t f;
r = sd_bus_message_read(message, "t", &f);
if (r < 0)
return r;
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
c->coredump_filter = f;
c->coredump_filter_set = true;
unit_write_settingf(u, flags, name, "CoredumpFilter=0x%"PRIx64, f);
}
return 1;
} else if (streq(name, "EnvironmentFiles")) {
_cleanup_free_ char *joined = NULL;

View File

@ -3323,6 +3323,14 @@ static int exec_child(
}
}
if (context->coredump_filter_set) {
r = set_coredump_filter(context->coredump_filter);
if (ERRNO_IS_PRIVILEGE(r))
log_unit_debug_errno(unit, r, "Failed to adjust coredump_filter, ignoring: %m");
else if (r < 0)
return log_unit_error_errno(unit, r, "Failed to adjust coredump_filter: %m");
}
if (context->nice_set) {
r = setpriority_closest(context->nice);
if (r < 0)
@ -4614,6 +4622,11 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
"%sOOMScoreAdjust: %i\n",
prefix, c->oom_score_adjust);
if (c->coredump_filter_set)
fprintf(f,
"%sCoredumpFilter: 0x%"PRIx64"\n",
prefix, c->coredump_filter);
for (i = 0; i < RLIM_NLIMITS; i++)
if (c->rlimit[i]) {
fprintf(f, "%sLimit%s: " RLIM_FMT "\n",

View File

@ -14,6 +14,7 @@ typedef struct Manager Manager;
#include <sys/capability.h>
#include "cgroup-util.h"
#include "coredump-util.h"
#include "cpu-set-util.h"
#include "exec-util.h"
#include "fdset.h"
@ -161,6 +162,7 @@ struct ExecContext {
bool working_directory_home:1;
bool oom_score_adjust_set:1;
bool coredump_filter_set:1;
bool nice_set:1;
bool ioprio_set:1;
bool cpu_sched_set:1;
@ -179,6 +181,7 @@ struct ExecContext {
int ioprio;
int cpu_sched_policy;
int cpu_sched_priority;
uint64_t coredump_filter;
CPUSet cpu_set;
NUMAPolicy numa_policy;

View File

@ -28,6 +28,7 @@ $1.Group, config_parse_user_group_compat, 0,
$1.SupplementaryGroups, config_parse_user_group_strv_compat, 0, offsetof($1, exec_context.supplementary_groups)
$1.Nice, config_parse_exec_nice, 0, offsetof($1, exec_context)
$1.OOMScoreAdjust, config_parse_exec_oom_score_adjust, 0, offsetof($1, exec_context)
$1.CoredumpFilter, config_parse_exec_coredump_filter, 0, offsetof($1, exec_context)
$1.IOSchedulingClass, config_parse_exec_io_class, 0, offsetof($1, exec_context)
$1.IOSchedulingPriority, config_parse_exec_io_priority, 0, offsetof($1, exec_context)
$1.CPUSchedulingPolicy, config_parse_exec_cpu_sched_policy, 0, offsetof($1, exec_context)

View File

@ -592,6 +592,45 @@ int config_parse_exec_oom_score_adjust(
return 0;
}
int config_parse_exec_coredump_filter(
const char* unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
ExecContext *c = data;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
if (isempty(rvalue)) {
c->coredump_filter = 0;
c->coredump_filter_set = false;
return 0;
}
uint64_t f;
r = coredump_filter_mask_from_string(rvalue, &f);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse the CoredumpFilter=%s, ignoring: %m", rvalue);
return 0;
}
c->coredump_filter |= f;
c->oom_score_adjust_set = true;
return 0;
}
int config_parse_exec(
const char *unit,
const char *filename,

View File

@ -26,6 +26,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_socket_protocol);
CONFIG_PARSER_PROTOTYPE(config_parse_socket_bind);
CONFIG_PARSER_PROTOTYPE(config_parse_exec_nice);
CONFIG_PARSER_PROTOTYPE(config_parse_exec_oom_score_adjust);
CONFIG_PARSER_PROTOTYPE(config_parse_exec_coredump_filter);
CONFIG_PARSER_PROTOTYPE(config_parse_exec);
CONFIG_PARSER_PROTOTYPE(config_parse_service_timeout);
CONFIG_PARSER_PROTOTYPE(config_parse_service_timeout_abort);

View File

@ -8,6 +8,7 @@
#include "cgroup-setup.h"
#include "cgroup-util.h"
#include "condition.h"
#include "coredump-util.h"
#include "cpu-set-util.h"
#include "escape.h"
#include "exec-util.h"
@ -119,6 +120,7 @@ DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, safe_atou64);
DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, mode_t, parse_mode);
DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, unsigned, safe_atou);
DEFINE_BUS_APPEND_PARSE_PTR("x", int64_t, int64_t, safe_atoi64);
DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, coredump_filter_mask_from_string);
static int bus_append_string(sd_bus_message *m, const char *field, const char *eq) {
int r;
@ -898,6 +900,9 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
"OOMScoreAdjust"))
return bus_append_safe_atoi(m, field, eq);
if (streq(field, "CoredumpFilter"))
return bus_append_coredump_filter_mask_from_string(m, field, eq);
if (streq(field, "Nice"))
return bus_append_parse_nice(m, field, eq);

View File

@ -374,6 +374,12 @@ static int bus_print_property(const char *name, const char *expected_value, sd_b
(void) format_timespan(timespan, sizeof(timespan), u, 0);
bus_print_property_value(name, expected_value, value, timespan);
} else if (streq(name, "CoredumpFilter")) {
char buf[STRLEN("0xFFFFFFFF")];
xsprintf(buf, "0x%"PRIx64, u);
bus_print_property_value(name, expected_value, value, buf);
} else if (streq(name, "RestrictNamespaces")) {
_cleanup_free_ char *s = NULL;
const char *result;

View File

@ -0,0 +1,74 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include "coredump-util.h"
#include "extract-word.h"
#include "fileio.h"
#include "string-table.h"
static const char *const coredump_filter_table[_COREDUMP_FILTER_MAX] = {
[COREDUMP_FILTER_PRIVATE_ANONYMOUS] = "private-anonymous",
[COREDUMP_FILTER_SHARED_ANONYMOUS] = "shared-anonymous",
[COREDUMP_FILTER_PRIVATE_FILE_BACKED] = "private-file-backed",
[COREDUMP_FILTER_SHARED_FILE_BACKED] = "shared-file-backed",
[COREDUMP_FILTER_ELF_HEADERS] = "elf-headers",
[COREDUMP_FILTER_PRIVATE_HUGE] = "private-huge",
[COREDUMP_FILTER_SHARED_HUGE] = "shared-huge",
[COREDUMP_FILTER_PRIVATE_DAX] = "private-dax",
[COREDUMP_FILTER_SHARED_DAX] = "shared-dax",
};
DEFINE_STRING_TABLE_LOOKUP(coredump_filter, CoredumpFilter);
int coredump_filter_mask_from_string(const char *s, uint64_t *ret) {
uint64_t m = 0;
assert(s);
assert(ret);
for (;;) {
_cleanup_free_ char *n = NULL;
CoredumpFilter v;
int r;
r = extract_first_word(&s, &n, NULL, 0);
if (r < 0)
return r;
if (r == 0)
break;
if (streq(n, "default")) {
m |= COREDUMP_FILTER_MASK_DEFAULT;
continue;
}
if (streq(n, "all")) {
m = UINT64_MAX;
continue;
}
v = coredump_filter_from_string(n);
if (v >= 0) {
m |= 1u << v;
continue;
}
uint64_t x;
r = safe_atoux64(n, &x);
if (r < 0)
return r;
m |= x;
}
*ret = m;
return 0;
}
int set_coredump_filter(uint64_t value) {
char t[STRLEN("0xFFFFFFFF")];
sprintf(t, "0x%"PRIx64, value);
return write_string_file("/proc/self/coredump_filter", t,
WRITE_STRING_FILE_VERIFY_ON_FAILURE|WRITE_STRING_FILE_DISABLE_BUFFER);
}

View File

@ -0,0 +1,29 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#include "macro.h"
typedef enum CoredumpFilter {
COREDUMP_FILTER_PRIVATE_ANONYMOUS = 0,
COREDUMP_FILTER_SHARED_ANONYMOUS,
COREDUMP_FILTER_PRIVATE_FILE_BACKED,
COREDUMP_FILTER_SHARED_FILE_BACKED,
COREDUMP_FILTER_ELF_HEADERS,
COREDUMP_FILTER_PRIVATE_HUGE,
COREDUMP_FILTER_SHARED_HUGE,
COREDUMP_FILTER_PRIVATE_DAX,
COREDUMP_FILTER_SHARED_DAX,
_COREDUMP_FILTER_MAX,
_COREDUMP_FILTER_INVALID = -1,
} CoredumpFilter;
#define COREDUMP_FILTER_MASK_DEFAULT (1u << COREDUMP_FILTER_PRIVATE_ANONYMOUS | \
1u << COREDUMP_FILTER_SHARED_ANONYMOUS | \
1u << COREDUMP_FILTER_ELF_HEADERS | \
1u << COREDUMP_FILTER_PRIVATE_HUGE)
const char* coredump_filter_to_string(CoredumpFilter i) _const_;
CoredumpFilter coredump_filter_from_string(const char *s) _pure_;
int coredump_filter_mask_from_string(const char *s, uint64_t *ret);
int set_coredump_filter(uint64_t value);

View File

@ -51,6 +51,8 @@ shared_sources = files('''
condition.h
conf-parser.c
conf-parser.h
coredump-util.c
coredump-util.h
cpu-set-util.c
cpu-set-util.h
crypt-util.c

View File

@ -588,6 +588,10 @@ tests += [
[],
[]],
[['src/test/test-coredump-util.c'],
[],
[]],
[['src/test/test-daemon.c'],
[],
[]],

View File

@ -0,0 +1,78 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include "alloc-util.h"
#include "coredump-util.h"
#include "macro.h"
#include "tests.h"
static void test_coredump_filter_to_from_string(void) {
log_info("/* %s */", __func__);
for (CoredumpFilter i = 0; i < _COREDUMP_FILTER_MAX; i++) {
const char *n;
assert_se(n = coredump_filter_to_string(i));
log_info("0x%x\t%s", 1<<i, n);
assert_se(coredump_filter_from_string(n) == i);
uint64_t f;
assert_se(coredump_filter_mask_from_string(n, &f) == 0);
assert_se(f == 1u << i);
}
}
static void test_coredump_filter_mask_from_string(void) {
log_info("/* %s */", __func__);
uint64_t f;
assert_se(coredump_filter_mask_from_string("default", &f) == 0);
assert_se(f == COREDUMP_FILTER_MASK_DEFAULT);
assert_se(coredump_filter_mask_from_string(" default\tdefault\tdefault ", &f) == 0);
assert_se(f == COREDUMP_FILTER_MASK_DEFAULT);
assert_se(coredump_filter_mask_from_string("defaulta", &f) < 0);
assert_se(coredump_filter_mask_from_string("default defaulta default", &f) < 0);
assert_se(coredump_filter_mask_from_string("default default defaulta", &f) < 0);
assert_se(coredump_filter_mask_from_string("private-anonymous default", &f) == 0);
assert_se(f == COREDUMP_FILTER_MASK_DEFAULT);
assert_se(coredump_filter_mask_from_string("shared-file-backed shared-dax", &f) == 0);
assert_se(f == (1 << COREDUMP_FILTER_SHARED_FILE_BACKED |
1 << COREDUMP_FILTER_SHARED_DAX));
assert_se(coredump_filter_mask_from_string("private-file-backed private-dax 0xF", &f) == 0);
assert_se(f == (1 << COREDUMP_FILTER_PRIVATE_FILE_BACKED |
1 << COREDUMP_FILTER_PRIVATE_DAX |
0xF));
assert_se(coredump_filter_mask_from_string("11", &f) == 0);
assert_se(f == 0x11);
assert_se(coredump_filter_mask_from_string("0x1101", &f) == 0);
assert_se(f == 0x1101);
assert_se(coredump_filter_mask_from_string("0", &f) == 0);
assert_se(f == 0);
assert_se(coredump_filter_mask_from_string("all", &f) == 0);
assert_se(FLAGS_SET(f, (1 << COREDUMP_FILTER_PRIVATE_ANONYMOUS |
1 << COREDUMP_FILTER_SHARED_ANONYMOUS |
1 << COREDUMP_FILTER_PRIVATE_FILE_BACKED |
1 << COREDUMP_FILTER_SHARED_FILE_BACKED |
1 << COREDUMP_FILTER_ELF_HEADERS |
1 << COREDUMP_FILTER_PRIVATE_HUGE |
1 << COREDUMP_FILTER_SHARED_HUGE |
1 << COREDUMP_FILTER_PRIVATE_DAX |
1 << COREDUMP_FILTER_SHARED_DAX)));
}
int main(int argc, char **argv) {
test_setup_logging(LOG_INFO);
test_coredump_filter_to_from_string();
test_coredump_filter_mask_from_string();
return 0;
}

View File

@ -561,6 +561,44 @@ static void test_safe_atoi64(void) {
assert_se(r == -EINVAL);
}
static void test_safe_atoux64(void) {
int r;
uint64_t l;
r = safe_atoux64("12345", &l);
assert_se(r == 0);
assert_se(l == 0x12345);
r = safe_atoux64(" 12345", &l);
assert_se(r == 0);
assert_se(l == 0x12345);
r = safe_atoux64("0x12345", &l);
assert_se(r == 0);
assert_se(l == 0x12345);
r = safe_atoux64("18446744073709551617", &l);
assert_se(r == -ERANGE);
r = safe_atoux64("-1", &l);
assert_se(r == -ERANGE);
r = safe_atoux64(" -1", &l);
assert_se(r == -ERANGE);
r = safe_atoux64("junk", &l);
assert_se(r == -EINVAL);
r = safe_atoux64("123x", &l);
assert_se(r == -EINVAL);
r = safe_atoux64("12.3", &l);
assert_se(r == -EINVAL);
r = safe_atoux64("", &l);
assert_se(r == -EINVAL);
}
static void test_safe_atod(void) {
int r;
double d;
@ -838,6 +876,7 @@ int main(int argc, char *argv[]) {
test_safe_atoux16();
test_safe_atou64();
test_safe_atoi64();
test_safe_atoux64();
test_safe_atod();
test_parse_percent();
test_parse_percent_unbounded();

View File

@ -44,6 +44,7 @@ BlockIOWeight=
BlockIOWriteBandwidth=
Broadcast=
BusName=
CoredumpFilter=
CPUAccounting=
CPUQuota=
CPUShares=