]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
analyze: add new fdstore verb
authorLennart Poettering <lennart@poettering.net>
Mon, 27 Mar 2023 16:16:03 +0000 (18:16 +0200)
committerLennart Poettering <lennart@poettering.net>
Wed, 29 Mar 2023 17:09:10 +0000 (19:09 +0200)
man/systemd-analyze.xml
man/systemd.service.xml
src/analyze/analyze-fdstore.c [new file with mode: 0644]
src/analyze/analyze-fdstore.h [new file with mode: 0644]
src/analyze/analyze.c
src/analyze/meson.build

index ad6d691a1d1fd2ddb7d0a2c55dbd8ef56b6c463c..9fd28e6f45c768e8089a61d0a8275a18166ab1b3 100644 (file)
       <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>
index e8be2ff46851f5c48e22bc62be3e287e550ae4ae..665128ee77ffd2ab6470a1528abd673f5c6a081c 100644 (file)
         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>
diff --git a/src/analyze/analyze-fdstore.c b/src/analyze/analyze-fdstore.c
new file mode 100644 (file)
index 0000000..13db7f5
--- /dev/null
@@ -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;
+}
diff --git a/src/analyze/analyze-fdstore.h b/src/analyze/analyze-fdstore.h
new file mode 100644 (file)
index 0000000..0b990db
--- /dev/null
@@ -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);
index 12c0bd653fa68d6dbcfe6ededeae2d4f8b78508c..0246da4b45dae0d2602140f223f9b893b54ca37d 100644 (file)
 #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           },
                 {}
         };
 
index ac40600a6dedd53325fee303e35385df97cf811b..695089a0beda7da92d29915db365807fd7e62f0e 100644 (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',