Skip to content

Commit 2eb46dc

Browse files
keszybzbluca
authored andcommitted
coredump: use %d in kernel core pattern
The kernel provides %d which is documented as "dump mode—same as value returned by prctl(2) PR_GET_DUMPABLE". We already query /proc/pid/auxv for this information, but unfortunately this check is subject to a race, because the crashed process may be replaced by an attacker before we read this data, for example replacing a SUID process that was killed by a signal with another process that is not SUID, tricking us into making the coredump of the original process readable by the attacker. With this patch, we effectively add one more check to the list of conditions that need be satisfied if we are to make the coredump accessible to the user. Reportedy-by: Qualys Security Advisory <qsa@qualys.com> (cherry-picked from commit 0c49e0049b7665bb7769a13ef346fef92e1ad4d6) (cherry-picked from commit c58a8a6ec9817275bb4babaa2c08e0e35090d4e3) (cherry picked from commit 19d439189ab85dd7222bdd59fd442bbcc8ea99a7) (cherry picked from commit 254ab8d) (cherry picked from commit 7fc7aa5) (cherry picked from commit 19b2286)
1 parent 2c81e60 commit 2eb46dc

File tree

4 files changed

+36
-4
lines changed

4 files changed

+36
-4
lines changed

man/systemd-coredump.xml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,18 @@ COREDUMP_FILENAME=/var/lib/systemd/coredump/core.Web….552351.….zst
273273
</listitem>
274274
</varlistentry>
275275

276+
<varlistentry>
277+
<term><varname>COREDUMP_DUMPABLE=</varname></term>
278+
279+
<listitem><para>The <constant>PR_GET_DUMPABLE</constant> field as reported by the kernel, see
280+
<citerefentry
281+
project='man-pages'><refentrytitle>prctl</refentrytitle><manvolnum>2</manvolnum></citerefentry>.
282+
</para>
283+
284+
<xi:include href="version-info.xml" xpointer="v258"/>
285+
</listitem>
286+
</varlistentry>
287+
276288
<varlistentry>
277289
<term><varname>COREDUMP_OPEN_FDS=</varname></term>
278290

src/coredump/coredump.c

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ typedef enum {
9595
_META_ARGV_REQUIRED,
9696
/* The fields below were added to kernel/core_pattern at later points, so they might be missing. */
9797
META_ARGV_HOSTNAME = _META_ARGV_REQUIRED, /* %h: hostname */
98+
META_ARGV_DUMPABLE, /* %d: as set by the kernel */
9899
/* If new fields are added, they should be added here, to maintain compatibility
99100
* with callers which don't know about the new fields. */
100101
_META_ARGV_MAX,
@@ -123,6 +124,7 @@ static const char * const meta_field_names[_META_MAX] = {
123124
[META_ARGV_TIMESTAMP] = "COREDUMP_TIMESTAMP=",
124125
[META_ARGV_RLIMIT] = "COREDUMP_RLIMIT=",
125126
[META_ARGV_HOSTNAME] = "COREDUMP_HOSTNAME=",
127+
[META_ARGV_DUMPABLE] = "COREDUMP_DUMPABLE=",
126128
[META_COMM] = "COREDUMP_COMM=",
127129
[META_EXE] = "COREDUMP_EXE=",
128130
[META_UNIT] = "COREDUMP_UNIT=",
@@ -133,6 +135,7 @@ typedef struct Context {
133135
const char *meta[_META_MAX];
134136
size_t meta_size[_META_MAX];
135137
pid_t pid;
138+
unsigned dumpable;
136139
bool is_pid1;
137140
bool is_journald;
138141
} Context;
@@ -448,14 +451,16 @@ static int grant_user_access(int core_fd, const Context *context) {
448451
if (r < 0)
449452
return r;
450453

451-
/* We allow access if we got all the data and at_secure is not set and
452-
* the uid/gid matches euid/egid. */
454+
/* We allow access if dumpable on the command line was exactly 1, we got all the data,
455+
* at_secure is not set, and the uid/gid match euid/egid. */
453456
bool ret =
457+
context->dumpable == 1 &&
454458
at_secure == 0 &&
455459
uid != UID_INVALID && euid != UID_INVALID && uid == euid &&
456460
gid != GID_INVALID && egid != GID_INVALID && gid == egid;
457-
log_debug("Will %s access (uid="UID_FMT " euid="UID_FMT " gid="GID_FMT " egid="GID_FMT " at_secure=%s)",
461+
log_debug("Will %s access (dumpable=%u uid="UID_FMT " euid="UID_FMT " gid="GID_FMT " egid="GID_FMT " at_secure=%s)",
458462
ret ? "permit" : "restrict",
463+
context->dumpable,
459464
uid, euid, gid, egid, yes_no(at_secure));
460465
return ret;
461466
}
@@ -1110,6 +1115,16 @@ static int save_context(Context *context, const struct iovec_wrapper *iovw) {
11101115
if (r < 0)
11111116
return log_error_errno(r, "Failed to parse PID \"%s\": %m", context->meta[META_ARGV_PID]);
11121117

1118+
/* The value is set to contents of /proc/sys/fs/suid_dumpable, which we set to 2,
1119+
* if the process is marked as not dumpable, see PR_SET_DUMPABLE(2const). */
1120+
if (context->meta[META_ARGV_DUMPABLE]) {
1121+
r = safe_atou(context->meta[META_ARGV_DUMPABLE], &context->dumpable);
1122+
if (r < 0)
1123+
return log_error_errno(r, "Failed to parse dumpable field \"%s\": %m", context->meta[META_ARGV_DUMPABLE]);
1124+
if (context->dumpable > 2)
1125+
log_notice("Got unexpected %%d/dumpable value %u.", context->dumpable);
1126+
}
1127+
11131128
unit = context->meta[META_UNIT];
11141129
context->is_pid1 = streq(context->meta[META_ARGV_PID], "1") || streq_ptr(unit, SPECIAL_INIT_SCOPE);
11151130
context->is_journald = streq_ptr(unit, SPECIAL_JOURNALD_SERVICE);

sysctl.d/50-coredump.conf.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
# the core dump.
1414
#
1515
# See systemd-coredump(8) and core(5).
16-
kernel.core_pattern=|{{ROOTLIBEXECDIR}}/systemd-coredump %P %u %g %s %t %c %h
16+
kernel.core_pattern=|{{ROOTLIBEXECDIR}}/systemd-coredump %P %u %g %s %t %c %h %d
1717

1818
# Allow 16 coredumps to be dispatched in parallel by the kernel.
1919
# We collect metadata from /proc/%P/, and thus need to make sure the crashed

test/units/testsuite-74.coredump.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,12 +163,17 @@ journalctl -b -n 1 --output=export --output-fields=MESSAGE,COREDUMP COREDUMP_EXE
163163
/usr/lib/systemd/systemd-coredump --backtrace $$ 0 0 6 1679509900 12345
164164
journalctl -b -n 1 --output=export --output-fields=MESSAGE,COREDUMP COREDUMP_EXE="/usr/bin/test-dump" |
165165
/usr/lib/systemd/systemd-coredump --backtrace $$ 0 0 6 1679509901 12345 mymachine
166+
journalctl -b -n 1 --output=export --output-fields=MESSAGE,COREDUMP COREDUMP_EXE="/usr/bin/test-dump" |
167+
/usr/lib/systemd/systemd-coredump --backtrace $$ 0 0 6 1679509902 12345 youmachine 1
166168
# Wait a bit for the coredumps to get processed
167169
timeout 30 bash -c "while [[ \$(coredumpctl list -q --no-legend $$ | wc -l) -lt 2 ]]; do sleep 1; done"
168170
coredumpctl info $$
169171
coredumpctl info COREDUMP_TIMESTAMP=1679509900000000
170172
coredumpctl info COREDUMP_TIMESTAMP=1679509901000000
171173
coredumpctl info COREDUMP_HOSTNAME="mymachine"
174+
coredumpctl info COREDUMP_TIMESTAMP=1679509902000000
175+
coredumpctl info COREDUMP_HOSTNAME="youmachine"
176+
coredumpctl info COREDUMP_DUMPABLE="1"
172177

173178
# This used to cause a stack overflow
174179
systemd-run -t --property CoredumpFilter=all ls /tmp

0 commit comments

Comments
 (0)