Skip to content

Commit 254ab8d

Browse files
committed
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 <[email protected]> (cherry-picked from commit 0c49e00) (cherry-picked from commit c58a8a6ec9817275bb4babaa2c08e0e35090d4e3) (cherry picked from commit 19d439189ab85dd7222bdd59fd442bbcc8ea99a7)
1 parent b46a4f0 commit 254ab8d

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
@@ -292,6 +292,18 @@ COREDUMP_FILENAME=/var/lib/systemd/coredump/core.Web….552351.….zst
292292
</listitem>
293293
</varlistentry>
294294

295+
<varlistentry>
296+
<term><varname>COREDUMP_DUMPABLE=</varname></term>
297+
298+
<listitem><para>The <constant>PR_GET_DUMPABLE</constant> field as reported by the kernel, see
299+
<citerefentry
300+
project='man-pages'><refentrytitle>prctl</refentrytitle><manvolnum>2</manvolnum></citerefentry>.
301+
</para>
302+
303+
<xi:include href="version-info.xml" xpointer="v258"/>
304+
</listitem>
305+
</varlistentry>
306+
295307
<varlistentry>
296308
<term><varname>COREDUMP_OPEN_FDS=</varname></term>
297309

src/coredump/coredump.c

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ typedef enum {
9898
_META_ARGV_REQUIRED,
9999
/* The fields below were added to kernel/core_pattern at later points, so they might be missing. */
100100
META_ARGV_HOSTNAME = _META_ARGV_REQUIRED, /* %h: hostname */
101+
META_ARGV_DUMPABLE, /* %d: as set by the kernel */
101102
/* If new fields are added, they should be added here, to maintain compatibility
102103
* with callers which don't know about the new fields. */
103104
_META_ARGV_MAX,
@@ -126,6 +127,7 @@ static const char * const meta_field_names[_META_MAX] = {
126127
[META_ARGV_TIMESTAMP] = "COREDUMP_TIMESTAMP=",
127128
[META_ARGV_RLIMIT] = "COREDUMP_RLIMIT=",
128129
[META_ARGV_HOSTNAME] = "COREDUMP_HOSTNAME=",
130+
[META_ARGV_DUMPABLE] = "COREDUMP_DUMPABLE=",
129131
[META_COMM] = "COREDUMP_COMM=",
130132
[META_EXE] = "COREDUMP_EXE=",
131133
[META_UNIT] = "COREDUMP_UNIT=",
@@ -138,6 +140,7 @@ typedef struct Context {
138140
pid_t pid;
139141
uid_t uid;
140142
gid_t gid;
143+
unsigned dumpable;
141144
bool is_pid1;
142145
bool is_journald;
143146
} Context;
@@ -396,14 +399,16 @@ static int grant_user_access(int core_fd, const Context *context) {
396399
if (r < 0)
397400
return r;
398401

399-
/* We allow access if we got all the data and at_secure is not set and
400-
* the uid/gid matches euid/egid. */
402+
/* We allow access if dumpable on the command line was exactly 1, we got all the data,
403+
* at_secure is not set, and the uid/gid match euid/egid. */
401404
bool ret =
405+
context->dumpable == 1 &&
402406
at_secure == 0 &&
403407
uid != UID_INVALID && euid != UID_INVALID && uid == euid &&
404408
gid != GID_INVALID && egid != GID_INVALID && gid == egid;
405-
log_debug("Will %s access (uid="UID_FMT " euid="UID_FMT " gid="GID_FMT " egid="GID_FMT " at_secure=%s)",
409+
log_debug("Will %s access (dumpable=%u uid="UID_FMT " euid="UID_FMT " gid="GID_FMT " egid="GID_FMT " at_secure=%s)",
406410
ret ? "permit" : "restrict",
411+
context->dumpable,
407412
uid, euid, gid, egid, yes_no(at_secure));
408413
return ret;
409414
}
@@ -994,6 +999,16 @@ static int save_context(Context *context, const struct iovec_wrapper *iovw) {
994999
if (r < 0)
9951000
return log_error_errno(r, "Failed to parse GID \"%s\": %m", context->meta[META_ARGV_GID]);
9961001

1002+
/* The value is set to contents of /proc/sys/fs/suid_dumpable, which we set to 2,
1003+
* if the process is marked as not dumpable, see PR_SET_DUMPABLE(2const). */
1004+
if (context->meta[META_ARGV_DUMPABLE]) {
1005+
r = safe_atou(context->meta[META_ARGV_DUMPABLE], &context->dumpable);
1006+
if (r < 0)
1007+
return log_error_errno(r, "Failed to parse dumpable field \"%s\": %m", context->meta[META_ARGV_DUMPABLE]);
1008+
if (context->dumpable > 2)
1009+
log_notice("Got unexpected %%d/dumpable value %u.", context->dumpable);
1010+
}
1011+
9971012
unit = context->meta[META_UNIT];
9981013
context->is_pid1 = streq(context->meta[META_ARGV_PID], "1") || streq_ptr(unit, SPECIAL_INIT_SCOPE);
9991014
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=|{{LIBEXECDIR}}/systemd-coredump %P %u %g %s %t %c %h
16+
kernel.core_pattern=|{{LIBEXECDIR}}/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
@@ -193,12 +193,17 @@ journalctl -b -n 1 --output=export --output-fields=MESSAGE,COREDUMP COREDUMP_EXE
193193
/usr/lib/systemd/systemd-coredump --backtrace $$ 0 0 6 1679509900 12345
194194
journalctl -b -n 1 --output=export --output-fields=MESSAGE,COREDUMP COREDUMP_EXE="/usr/bin/test-dump" |
195195
/usr/lib/systemd/systemd-coredump --backtrace $$ 0 0 6 1679509901 12345 mymachine
196+
journalctl -b -n 1 --output=export --output-fields=MESSAGE,COREDUMP COREDUMP_EXE="/usr/bin/test-dump" |
197+
/usr/lib/systemd/systemd-coredump --backtrace $$ 0 0 6 1679509902 12345 youmachine 1
196198
# Wait a bit for the coredumps to get processed
197199
timeout 30 bash -c "while [[ \$(coredumpctl list -q --no-legend $$ | wc -l) -lt 2 ]]; do sleep 1; done"
198200
coredumpctl info $$
199201
coredumpctl info COREDUMP_TIMESTAMP=1679509900000000
200202
coredumpctl info COREDUMP_TIMESTAMP=1679509901000000
201203
coredumpctl info COREDUMP_HOSTNAME="mymachine"
204+
coredumpctl info COREDUMP_TIMESTAMP=1679509902000000
205+
coredumpctl info COREDUMP_HOSTNAME="youmachine"
206+
coredumpctl info COREDUMP_DUMPABLE="1"
202207

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

0 commit comments

Comments
 (0)