Skip to content

Commit

Permalink
analyze: add inspect-elf verb to parse package metadata
Browse files Browse the repository at this point in the history
Parses and prints package metadata from executables, libraries and core files

$ systemd-analyze inspect-elf /tmp/core.fsverity.1000.f77dac5dc161402aa44e15b7dd9dcf97.58561.1637106137000000 ~/git/fsverity-utils/libfsverity.so.0
FILE         /TMP/CORE.FSVERITY.1000.F77DAC5DC161402AA44E15B7DD9DCF97.58561.1637106137000000
module name  /home/luca/git/fsverity-utils/fsverity
type         deb
name         fsverity-utils
version      1.3-1
architecture amd64
os           debian
debugInfoUrl https://debuginfod.debian.net
buildId      f70ffd61ea22aee78c33c56aeda61c63309a55e3
FILE         /HOME/LUCA/GIT/FSVERITY-UTILS/LIBFSVERITY.SO.0
type         deb
name         fsverity-utils
version      1.3-1
architecture amd64
os           debian
debugInfoUrl https://debuginfod.debian.net
buildId      bb9b8587ab7d114b0ddd762d8a1c030dee96fe2f
$ systemd-analyze inspect-elf /tmp/core.fsverity.1000.f77dac5dc161402aa44e15b7dd9dcf97.58561.1637106137000000 ~/git/fsverity-utils/libfsverity.so.0  --json=pretty
{
        "/home/luca/git/fsverity-utils/fsverity" : {
                "type" : "deb",
                "name" : "fsverity-utils",
                "version" : "1.3-1",
                "architecture" : "amd64",
                "os" : "debian",
                "debugInfoUrl" : "https://debuginfod.debian.net",
                "buildId" : "f70ffd61ea22aee78c33c56aeda61c63309a55e3"
        }
}
{
        "/home/luca/git/fsverity-utils/libfsverity.so.0" : {
                "type" : "deb",
                "name" : "fsverity-utils",
                "version" : "1.3-1",
                "architecture" : "amd64",
                "os" : "debian",
                "debugInfoUrl" : "https://debuginfod.debian.net",
                "buildId" : "bb9b8587ab7d114b0ddd762d8a1c030dee96fe2f"
        }
}
  • Loading branch information
bluca committed Nov 22, 2021
1 parent d73804b commit 2ba2ef0
Show file tree
Hide file tree
Showing 8 changed files with 143 additions and 1 deletion.
26 changes: 26 additions & 0 deletions man/systemd-analyze.xml
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,32 @@ $ systemd-analyze verify /tmp/source:alias.service
</programlisting>
</example>
</refsect2>

<refsect2>
<title><command>systemd-analyze inspect-elf <replaceable>FILE</replaceable>...</command></title>

<para>This command will load the specified file(s), and if they are ELF objects (executables,
libraries, core files, etc.) it will parse the embedded packaging metadata, if any, and print
it in a table or json format. See the <ulink url="https://systemd.io/COREDUMP_PACKAGE_METADATA/">
Packaging Metadata</ulink> documentation for more information.</para>

<example>
<title>Table output</title>

<programlisting>$ systemd-analyze inspect-elf /tmp/core.fsverity.1000.f77dac5dc161402aa44e15b7dd9dcf97.58561.1637106137000000
FILE /TMP/CORE.FSVERITY.1000.F77DAC5DC161402AA44E15B7DD9DCF97.58561.1637106137000000
module name /usr/bin/fsverity
type deb
name fsverity-utils
version 1.3-1
architecture amd64
os debian
debugInfoUrl https://debuginfod.debian.net
buildId bb9b8587ab7d114b0ddd762d8a1c030dee96fe2
</programlisting>
</example>

</refsect2>
</refsect1>

<refsect1>
Expand Down
9 changes: 9 additions & 0 deletions shell-completion/bash/systemd-analyze
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ _systemd_analyze() {
[CAT_CONFIG]='cat-config'
[SECURITY]='security'
[CONDITION]='condition'
[INSPECT_ELF]='inspect-elf'
)

local CONFIGS='systemd/bootchart.conf systemd/coredump.conf systemd/journald.conf
Expand Down Expand Up @@ -166,6 +167,14 @@ _systemd_analyze() {
fi
comps=$( __get_services $mode )
fi

elif __contains_word "$verb" ${VERBS[INSPECT_ELF]}; then
if [[ $cur = -* ]]; then
comps='--help --version --json=off --json=pretty --json=short'
else
comps=$( compgen -A file -- "$cur" )
compopt -o filenames
fi
fi

COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
Expand Down
1 change: 1 addition & 0 deletions shell-completion/zsh/_systemd-analyze
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
'timestamp:Parse a systemd syntax timestamp'
'timespan:Parse a systemd syntax timespan'
'security:Analyze security settings of a service'
'inspect-elf:Parse and print ELF package metadata'
# log-level, log-target, service-watchdogs have been deprecated
)

Expand Down
84 changes: 84 additions & 0 deletions src/analyze/analyze-elf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */


#include "analyze-elf.h"
#include "elf-util.h"
#include "errno-util.h"
#include "fd-util.h"
#include "format-table.h"
#include "format-util.h"
#include "json.h"
#include "path-util.h"
#include "strv.h"

int analyze_elf(char **filenames, JsonFormatFlags json_flags) {
char **filename;
int r;

STRV_FOREACH(filename, filenames) {
_cleanup_(json_variant_unrefp) JsonVariant *package_metadata = NULL;
_cleanup_(table_unrefp) Table *t = NULL;
_cleanup_free_ char *abspath = NULL;
_cleanup_close_ int fd = -1;

r = path_make_absolute_cwd(*filename, &abspath);
if (r < 0)
return log_error_errno(r, "Could not make an absolute path out of \"%s\": %m", *filename);

path_simplify(abspath);

fd = RET_NERRNO(open(abspath, O_RDONLY|O_CLOEXEC));
if (fd < 0)
return log_error_errno(fd, "Could not open \"%s\": %m", abspath);

r = parse_elf_object(fd, abspath, NULL, &package_metadata);
if (r < 0)
return log_error_errno(r, "Parsing \"%s\" as ELF object failed: %m", abspath);

t = table_new("file", abspath);
if (!t)
return log_oom();

if (package_metadata) {
const char *module_name;
JsonVariant *module_json;

JSON_VARIANT_OBJECT_FOREACH(module_name, module_json, package_metadata) {
JsonVariant *field;
const char *field_name;

/* In case of core files the module name will be the executable,
* but for binaries/libraries it's just the path, so don't print it
* twice. */
if (!streq(abspath, module_name)) {
r = table_add_many(
t,
TABLE_STRING, "module name",
TABLE_STRING, module_name);
if (r < 0)
return table_log_add_error(r);
}

JSON_VARIANT_OBJECT_FOREACH(field_name, field, module_json)
if (json_variant_is_string(field)) {
r = table_add_many(
t,
TABLE_STRING, field_name,
TABLE_STRING, json_variant_string(field));
if (r < 0)
return table_log_add_error(r);
}
}
}
if (json_flags & JSON_FORMAT_OFF) {
(void) table_set_header(t, true);

r = table_print(t, NULL);
if (r < 0)
return table_log_print_error(r);
} else
json_variant_dump(package_metadata, json_flags, stdout, NULL);
}

return 0;
}
6 changes: 6 additions & 0 deletions src/analyze/analyze-elf.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once

#include "json.h"

int analyze_elf(char **filenames, JsonFormatFlags json_flags);
11 changes: 10 additions & 1 deletion src/analyze/analyze.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

#include "alloc-util.h"
#include "analyze-condition.h"
#include "analyze-elf.h"
#include "analyze-security.h"
#include "analyze-verify.h"
#include "bus-error.h"
Expand Down Expand Up @@ -2428,6 +2429,12 @@ static int do_security(int argc, char *argv[], void *userdata) {
/*flags=*/ 0);
}

static int do_elf_inspection(int argc, char *argv[], void *userdata) {
pager_open(arg_pager_flags);

return analyze_elf(strv_skip(argv, 1), arg_json_format_flags);
}

static int help(int argc, char *argv[], void *userdata) {
_cleanup_free_ char *link = NULL, *dot_link = NULL;
int r;
Expand Down Expand Up @@ -2470,6 +2477,7 @@ static int help(int argc, char *argv[], void *userdata) {
" timestamp TIMESTAMP... Validate a timestamp\n"
" timespan SPAN... Validate a time span\n"
" security [UNIT...] Analyze security of unit\n"
" inspect-elf FILE... Parse and print ELF package metadata\n"
"\nOptions:\n"
" --recursive-errors=MODE Control which units are verified\n"
" --offline=BOOL Perform a security review on unit file(s)\n"
Expand Down Expand Up @@ -2734,7 +2742,7 @@ 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 && !streq_ptr(argv[optind], "security"))
if (arg_json_format_flags != JSON_FORMAT_OFF && !STRPTR_IN_SET(argv[optind], "security", "inspect-elf"))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Option --json= is only supported for security right now.");

Expand Down Expand Up @@ -2810,6 +2818,7 @@ static int run(int argc, char *argv[]) {
{ "timestamp", 2, VERB_ANY, 0, test_timestamp },
{ "timespan", 2, VERB_ANY, 0, dump_timespan },
{ "security", VERB_ANY, VERB_ANY, 0, do_security },
{ "inspect-elf", 2, VERB_ANY, 0, do_elf_inspection },
{}
};

Expand Down
2 changes: 2 additions & 0 deletions src/analyze/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ systemd_analyze_sources = files('''
analyze.c
analyze-condition.c
analyze-condition.h
analyze-elf.c
analyze-elf.h
analyze-verify.c
analyze-verify.h
analyze-security.c
Expand Down
5 changes: 5 additions & 0 deletions test/units/testsuite-65.sh
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,11 @@ set -e

rm /tmp/img/usr/lib/systemd/system/testfile.service

# The env binary (used as shebang) should at least have a buildId, so test the ELF parsing functionality
if systemd-analyze --version | grep -q -F "+ELFUTILS"; then
systemd-analyze inspect-elf /usr/bin/env --json=pretty | grep -q -F "buildId"
fi

systemd-analyze log-level info

echo OK >/testok
Expand Down

0 comments on commit 2ba2ef0

Please sign in to comment.