analyze: add new fdstore verb

This commit is contained in:
Lennart Poettering 2023-03-27 18:16:03 +02:00
parent 2ea24611b9
commit 5f43c97cd2
6 changed files with 170 additions and 5 deletions

View file

@ -156,6 +156,12 @@
<arg choice="plain">malloc</arg>
<arg choice="opt" rep="repeat"><replaceable>D-BUS SERVICE</replaceable></arg>
</cmdsynopsis>
<cmdsynopsis>
<command>systemd-analyze</command>
<arg choice="opt" rep="repeat">OPTIONS</arg>
<arg choice="plain">fdstore</arg>
<arg choice="opt" rep="repeat"><replaceable>UNIT</replaceable></arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1>
@ -803,8 +809,37 @@ $ systemd-analyze verify /tmp/source:alias.service
}
</programlisting>
</example>
</refsect2>
<refsect2>
<title><command>systemd-analyze fdstore <optional><replaceable>UNIT</replaceable>...</optional></command></title>
<para>Lists the current contents of the specified service unit's file descriptor store. This shows
names, inode types, device numbers, inode numbers, paths and open modes of the open file
descriptors. The specified units must have <varname>FileDescriptorStoreMax=</varname> enabled, see
<citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
details.</para>
<example>
<title>Table output</title>
<programlisting>$ systemd-analyze fdstore systemd-journald.service
FDNAME TYPE DEVNO INODE RDEVNO PATH FLAGS
stored sock 0:8 4218620 - socket:[4218620] ro
stored sock 0:8 4213198 - socket:[4213198] ro
stored sock 0:8 4213190 - socket:[4213190] ro
</programlisting>
</example>
<para>Note: the "DEVNO" column refers to the major/minor numbers of the device node backing the file
system the file descriptor's inode is on. The "RDEVNO" column refers to the major/minor numbers of the
device node itself if the file descriptor refers to one. Compare with corresponding
<varname>.st_dev</varname> and <varname>.st_rdev</varname> fields in <type>struct stat</type> (see
<citerefentry
project='man-pages'><refentrytitle>stat</refentrytitle><manvolnum>2</manvolnum></citerefentry> for
details). The listed inode numbers in the "INODE" column are on the file system indicated by
"DEVNO".</para>
</refsect2>
</refsect1>
<refsect1>

View file

@ -1141,7 +1141,18 @@
fully stopped and no job is queued or being executed for it. If this option is used,
<varname>NotifyAccess=</varname> (see above) should be set to open access to the notification socket
provided by systemd. If <varname>NotifyAccess=</varname> is not set, it will be implicitly set to
<option>main</option>.</para></listitem>
<option>main</option>.</para>
<para>The <command>fdstore</command> command of
<citerefentry><refentrytitle>systemd-analyze</refentrytitle><manvolnum>1</manvolnum></citerefentry>
may be used to list the current contents of a service's file descriptor store.</para>
<para>Note that the service manager will only pass file descriptors contained in the file descriptor
store to the service's own processes, never to other clients via IPC or similar. However, it does
allow unprivileged clients to query the list of currently open file descriptors of a
service. Sensitive data may hence be safely placed inside the referenced files, but should not be
attached to the metadata (e.g. included in filenames) of the stored file
descriptors.</para></listitem>
</varlistentry>
<varlistentry>

View file

@ -0,0 +1,110 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "analyze-fdstore.h"
#include "analyze.h"
#include "bus-error.h"
#include "bus-locator.h"
#include "fd-util.h"
#include "format-table.h"
static int dump_fdstore(sd_bus *bus, const char *arg) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_(table_unrefp) Table *table = NULL;
_cleanup_free_ char *unit = NULL;
int r;
assert(bus);
assert(arg);
r = unit_name_mangle_with_suffix(arg, NULL, UNIT_NAME_MANGLE_GLOB, ".service", &unit);
if (r < 0)
return log_error_errno(r, "Failed to mangle name '%s': %m", arg);
r = bus_call_method(
bus,
bus_systemd_mgr,
"DumpUnitFileDescriptorStore",
&error,
&reply,
"s", unit);
if (r < 0)
return log_error_errno(r, "Failed to call DumpUnitFileDescriptorStore: %s",
bus_error_message(&error, r));
r = sd_bus_message_enter_container(reply, 'a', "(suuutuusu)");
if (r < 0)
return bus_log_parse_error(r);
table = table_new("fdname", "type", "devno", "inode", "rdevno", "path", "flags");
if (!table)
return log_oom();
table_set_ersatz_string(table, TABLE_ERSATZ_DASH);
(void) table_set_align_percent(table, TABLE_HEADER_CELL(3), 100);
for (;;) {
uint32_t mode, major, minor, rmajor, rminor, flags;
const char *fdname, *path;
uint64_t inode;
r = sd_bus_message_read(
reply,
"(suuutuusu)",
&fdname,
&mode,
&major, &minor,
&inode,
&rmajor, &rminor,
&path,
&flags);
if (r < 0)
return bus_log_parse_error(r);
if (r == 0)
break;
r = table_add_many(
table,
TABLE_STRING, fdname,
TABLE_MODE_INODE_TYPE, mode,
TABLE_DEVNUM, makedev(major, minor),
TABLE_UINT64, inode,
TABLE_DEVNUM, makedev(rmajor, rminor),
TABLE_PATH, path,
TABLE_STRING, accmode_to_string(flags));
if (r < 0)
return table_log_add_error(r);
}
r = sd_bus_message_exit_container(reply);
if (r < 0)
return r;
if (FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF) && table_get_rows(table) <= 0)
log_info("No file descriptors in fdstore of '%s'.", unit);
else {
r = table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, /* show_header= */true);
if (r < 0)
return log_error_errno(r, "Failed to output table: %m");
}
return EXIT_SUCCESS;
}
int verb_fdstore(int argc, char *argv[], void *userdata) {
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
int r;
r = acquire_bus(&bus, NULL);
if (r < 0)
return bus_log_connect_error(r, arg_transport);
STRV_FOREACH(arg, strv_skip(argv, 1)) {
r = dump_fdstore(bus, *arg);
if (r < 0)
return r;
}
return EXIT_SUCCESS;
}

View file

@ -0,0 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "sd-bus.h"
int verb_fdstore(int argc, char *argv[], void *userdata);

View file

@ -17,11 +17,13 @@
#include "analyze-calendar.h"
#include "analyze-capability.h"
#include "analyze-cat-config.h"
#include "analyze-compare-versions.h"
#include "analyze-condition.h"
#include "analyze-critical-chain.h"
#include "analyze-dot.h"
#include "analyze-dump.h"
#include "analyze-exit-status.h"
#include "analyze-fdstore.h"
#include "analyze-filesystems.h"
#include "analyze-inspect-elf.h"
#include "analyze-log-control.h"
@ -36,7 +38,6 @@
#include "analyze-timestamp.h"
#include "analyze-unit-files.h"
#include "analyze-unit-paths.h"
#include "analyze-compare-versions.h"
#include "analyze-verify.h"
#include "build.h"
#include "bus-error.h"
@ -229,6 +230,7 @@ static int help(int argc, char *argv[], void *userdata) {
" security [UNIT...] Analyze security of unit\n"
" inspect-elf FILE... Parse and print ELF package metadata\n"
" malloc [D-BUS SERVICE...] Dump malloc stats of a D-Bus service\n"
" fdstore SERVICE... Show file descriptor store contents of service\n"
"\nOptions:\n"
" --recursive-errors=MODE Control which units are verified\n"
" --offline=BOOL Perform a security review on unit file(s)\n"
@ -531,9 +533,9 @@ static int parse_argv(int argc, char *argv[]) {
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Option --offline= is only supported for security right now.");
if (arg_json_format_flags != JSON_FORMAT_OFF && !STRPTR_IN_SET(argv[optind], "security", "inspect-elf", "plot"))
if (arg_json_format_flags != JSON_FORMAT_OFF && !STRPTR_IN_SET(argv[optind], "security", "inspect-elf", "plot", "fdstore"))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Option --json= is only supported for security, inspect-elf, and plot right now.");
"Option --json= is only supported for security, inspect-elf, plot, and fdstore right now.");
if (arg_threshold != 100 && !streq_ptr(argv[optind], "security"))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
@ -620,6 +622,7 @@ static int run(int argc, char *argv[]) {
{ "security", VERB_ANY, VERB_ANY, 0, verb_security },
{ "inspect-elf", 2, VERB_ANY, 0, verb_elf_inspection },
{ "malloc", VERB_ANY, VERB_ANY, 0, verb_malloc },
{ "fdstore", 2, VERB_ANY, 0, verb_fdstore },
{}
};

View file

@ -11,6 +11,7 @@ systemd_analyze_sources = files(
'analyze-dot.c',
'analyze-dump.c',
'analyze-exit-status.c',
'analyze-fdstore.c',
'analyze-filesystems.c',
'analyze-inspect-elf.c',
'analyze-log-control.c',