X Tutup
Skip to content

Commit 917e655

Browse files
committed
analyze: add inspect-elf verb to parse package metadata
Parses and prints package metadata from executables, libraries and core files $ systemd-analyze inspect-elf /tmp/core ../fsverity-utils/fsverityb /bin/bash --json=off --no-pager __________________________ path: /tmp/core elfType: coredump elfArchitecture: AMD x86-64 module name: /tmp/crash type: deb name: hello version: 1.0 architecture: amd64 os: debian osVersion: 11 buildId: b33541096a09c29a0ba4ec5c69364a2711b7c269 module name: /usr/lib/x86_64-linux-gnu/libc-2.31.so type: deb name: hello version: 1.0 architecture: amd64 os: debian osVersion: 11 buildId: 54eef5ce96cf37cb175b0d93186836ca1caf470c module name: /usr/lib/x86_64-linux-gnu/ld-2.31.so type: deb name: hello version: 1.0 architecture: amd64 os: debian osVersion: 11 buildId: 32438eb3b034da54caf58c7a65446639f7cfe274 __________________________________________________________________ path: /home/luca/git/systemd/../fsverity-utils/fsverity elfType: executable elfArchitecture: AMD x86-64 type: deb name: fsverity-utils version: 1.3-1 architecture: amd64 os: debian debugInfoUrl: https://debuginfod.debian.net buildId: 05b899e6ee0d3653e20458719b202ed3ca8d566f _________________________ path: /bin/bash elfType: executable elfArchitecture: AMD x86-64 buildId: 4fef260f60e257d2dbd4126bf8add83837aea190 $ $ systemd-analyze inspect-elf /tmp/core ../fsverity-utils/fsverity /bin/bash /tmp/core.test-condition.1000.f9b9a84a9fd1482c9702d6afa6f6934b.37640.1637083078000000 --json=pretty --no-pager { "elfType" : "coredump", "elfArchitecture" : "AMD x86-64", "/home/bluca/git/fsverity-utils/fsverity" : { "type" : "deb", "name" : "fsverity-utils", "version" : "1.3-1", "buildId" : "7c895ecd2a271f93e96268f479fdc3c64a2ec4ee" }, "/home/bluca/git/fsverity-utils/libfsverity.so.0" : { "type" : "deb", "name" : "fsverity-utils", "version" : "1.3-1", "buildId" : "b5e428254abf14237b0ae70ed85fffbb98a78f88" } } { "elfType" : "executable", "elfArchitecture" : "AMD x86-64", "/home/bluca/git/systemd/../fsverity-utils/fsverity" : { "type" : "deb", "name" : "fsverity-utils", "version" : "1.3-1", "buildId" : "7c895ecd2a271f93e96268f479fdc3c64a2ec4ee" } } { "elfType" : "executable", "elfArchitecture" : "AMD x86-64", "/bin/bash" : { "buildId" : "3313b4cb119dcce16927a9b6cc61dcd97dfc4d59" } } { "elfType" : "coredump", "elfArchitecture" : "AMD x86-64" }
1 parent d48c272 commit 917e655

File tree

8 files changed

+193
-1
lines changed

8 files changed

+193
-1
lines changed

man/systemd-analyze.xml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -681,6 +681,39 @@ $ systemd-analyze verify /tmp/source:alias.service
681681
</programlisting>
682682
</example>
683683
</refsect2>
684+
685+
<refsect2>
686+
<title><command>systemd-analyze inspect-elf <replaceable>FILE</replaceable>...</command></title>
687+
688+
<para>This command will load the specified file(s), and if they are ELF objects (executables,
689+
libraries, core files, etc.) it will parse the embedded packaging metadata, if any, and print
690+
it in a table or json format. See the <ulink url="https://systemd.io/COREDUMP_PACKAGE_METADATA/">
691+
Packaging Metadata</ulink> documentation for more information.</para>
692+
693+
<example>
694+
<title>Table output</title>
695+
696+
<programlisting>$ systemd-analyze inspect-elf --json=pretty /tmp/core.fsverity.1000.f77dac5dc161402aa44e15b7dd9dcf97.58561.1637106137000000
697+
{
698+
"elfType" : "coredump",
699+
"elfArchitecture" : "AMD x86-64",
700+
"/home/bluca/git/fsverity-utils/fsverity" : {
701+
"type" : "deb",
702+
"name" : "fsverity-utils",
703+
"version" : "1.3-1",
704+
"buildId" : "7c895ecd2a271f93e96268f479fdc3c64a2ec4ee"
705+
},
706+
"/home/bluca/git/fsverity-utils/libfsverity.so.0" : {
707+
"type" : "deb",
708+
"name" : "fsverity-utils",
709+
"version" : "1.3-1",
710+
"buildId" : "b5e428254abf14237b0ae70ed85fffbb98a78f88"
711+
}
712+
}
713+
</programlisting>
714+
</example>
715+
716+
</refsect2>
684717
</refsect1>
685718

686719
<refsect1>

shell-completion/bash/systemd-analyze

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ _systemd_analyze() {
6363
[CAT_CONFIG]='cat-config'
6464
[SECURITY]='security'
6565
[CONDITION]='condition'
66+
[INSPECT_ELF]='inspect-elf'
6667
)
6768

6869
local CONFIGS='systemd/bootchart.conf systemd/coredump.conf systemd/journald.conf
@@ -169,6 +170,14 @@ _systemd_analyze() {
169170
fi
170171
comps=$( __get_services $mode )
171172
fi
173+
174+
elif __contains_word "$verb" ${VERBS[INSPECT_ELF]}; then
175+
if [[ $cur = -* ]]; then
176+
comps='--help --version --json=off --json=pretty --json=short'
177+
else
178+
comps=$( compgen -A file -- "$cur" )
179+
compopt -o filenames
180+
fi
172181
fi
173182

174183
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )

shell-completion/zsh/_systemd-analyze

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
'timestamp:Parse a systemd syntax timestamp'
5555
'timespan:Parse a systemd syntax timespan'
5656
'security:Analyze security settings of a service'
57+
'inspect-elf:Parse and print ELF package metadata'
5758
# log-level, log-target, service-watchdogs have been deprecated
5859
)
5960

src/analyze/analyze-elf.c

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2+
3+
#include "analyze-elf.h"
4+
#include "elf-util.h"
5+
#include "errno-util.h"
6+
#include "fd-util.h"
7+
#include "format-table.h"
8+
#include "format-util.h"
9+
#include "json.h"
10+
#include "path-util.h"
11+
#include "strv.h"
12+
13+
int analyze_elf(char **filenames, JsonFormatFlags json_flags) {
14+
char **filename;
15+
int r;
16+
17+
STRV_FOREACH(filename, filenames) {
18+
_cleanup_(json_variant_unrefp) JsonVariant *package_metadata = NULL;
19+
_cleanup_(table_unrefp) Table *t = NULL;
20+
_cleanup_free_ char *abspath = NULL;
21+
_cleanup_close_ int fd = -1;
22+
23+
r = path_make_absolute_cwd(*filename, &abspath);
24+
if (r < 0)
25+
return log_error_errno(r, "Could not make an absolute path out of \"%s\": %m", *filename);
26+
27+
path_simplify(abspath);
28+
29+
fd = RET_NERRNO(open(abspath, O_RDONLY|O_CLOEXEC));
30+
if (fd < 0)
31+
return log_error_errno(fd, "Could not open \"%s\": %m", abspath);
32+
33+
r = parse_elf_object(fd, abspath, /* fork_disable_dump= */false, NULL, &package_metadata);
34+
if (r < 0)
35+
return log_error_errno(r, "Parsing \"%s\" as ELF object failed: %m", abspath);
36+
37+
t = table_new("", "");
38+
if (!t)
39+
return log_oom();
40+
41+
r = table_set_align_percent(t, TABLE_HEADER_CELL(0), 100);
42+
if (r < 0)
43+
return table_log_add_error(r);
44+
45+
r = table_add_many(
46+
t,
47+
TABLE_STRING, "path:",
48+
TABLE_STRING, abspath);
49+
if (r < 0)
50+
return table_log_add_error(r);
51+
52+
if (package_metadata) {
53+
JsonVariant *module_json;
54+
const char *module_name;
55+
56+
JSON_VARIANT_OBJECT_FOREACH(module_name, module_json, package_metadata) {
57+
const char *field_name;
58+
JsonVariant *field;
59+
60+
/* The ELF type and architecture are added as top-level objects,
61+
* since they are only parsed for the file itself, but the packaging
62+
* metadata is parsed recursively in core files, so there might be
63+
* multiple modules. */
64+
if (STR_IN_SET(module_name, "elfType", "elfArchitecture")) {
65+
_cleanup_free_ char *suffixed = NULL;
66+
67+
suffixed = strjoin(module_name, ":");
68+
if (!suffixed)
69+
return log_oom();
70+
71+
r = table_add_many(
72+
t,
73+
TABLE_STRING, suffixed,
74+
TABLE_STRING, json_variant_string(module_json));
75+
if (r < 0)
76+
return table_log_add_error(r);
77+
78+
continue;
79+
}
80+
81+
/* path/elfType/elfArchitecture come first just once per file,
82+
* then we might have multiple modules, so add a separator between
83+
* them to make the output more readable. */
84+
r = table_add_many(t, TABLE_EMPTY, TABLE_EMPTY);
85+
if (r < 0)
86+
return table_log_add_error(r);
87+
88+
/* In case of core files the module name will be the executable,
89+
* but for binaries/libraries it's just the path, so don't print it
90+
* twice. */
91+
if (!streq(abspath, module_name)) {
92+
r = table_add_many(
93+
t,
94+
TABLE_STRING, "module name:",
95+
TABLE_STRING, module_name);
96+
if (r < 0)
97+
return table_log_add_error(r);
98+
}
99+
100+
JSON_VARIANT_OBJECT_FOREACH(field_name, field, module_json)
101+
if (json_variant_is_string(field)) {
102+
_cleanup_free_ char *suffixed = NULL;
103+
104+
suffixed = strjoin(field_name, ":");
105+
if (!suffixed)
106+
return log_oom();
107+
108+
r = table_add_many(
109+
t,
110+
TABLE_STRING, suffixed,
111+
TABLE_STRING, json_variant_string(field));
112+
if (r < 0)
113+
return table_log_add_error(r);
114+
}
115+
}
116+
}
117+
if (json_flags & JSON_FORMAT_OFF) {
118+
(void) table_set_header(t, true);
119+
120+
r = table_print(t, NULL);
121+
if (r < 0)
122+
return table_log_print_error(r);
123+
} else
124+
json_variant_dump(package_metadata, json_flags, stdout, NULL);
125+
}
126+
127+
return 0;
128+
}

src/analyze/analyze-elf.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2+
#pragma once
3+
4+
#include "json.h"
5+
6+
int analyze_elf(char **filenames, JsonFormatFlags json_flags);

src/analyze/analyze.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
#include "alloc-util.h"
1515
#include "analyze-condition.h"
16+
#include "analyze-elf.h"
1617
#include "analyze-security.h"
1718
#include "analyze-verify.h"
1819
#include "bus-error.h"
@@ -2431,6 +2432,12 @@ static int do_security(int argc, char *argv[], void *userdata) {
24312432
/*flags=*/ 0);
24322433
}
24332434

2435+
static int do_elf_inspection(int argc, char *argv[], void *userdata) {
2436+
pager_open(arg_pager_flags);
2437+
2438+
return analyze_elf(strv_skip(argv, 1), arg_json_format_flags);
2439+
}
2440+
24342441
static int help(int argc, char *argv[], void *userdata) {
24352442
_cleanup_free_ char *link = NULL, *dot_link = NULL;
24362443
int r;
@@ -2473,6 +2480,7 @@ static int help(int argc, char *argv[], void *userdata) {
24732480
" timestamp TIMESTAMP... Validate a timestamp\n"
24742481
" timespan SPAN... Validate a time span\n"
24752482
" security [UNIT...] Analyze security of unit\n"
2483+
" inspect-elf FILE... Parse and print ELF package metadata\n"
24762484
"\nOptions:\n"
24772485
" --recursive-errors=MODE Control which units are verified\n"
24782486
" --offline=BOOL Perform a security review on unit file(s)\n"
@@ -2759,7 +2767,7 @@ static int parse_argv(int argc, char *argv[]) {
27592767
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
27602768
"Option --offline= is only supported for security right now.");
27612769

2762-
if (arg_json_format_flags != JSON_FORMAT_OFF && !streq_ptr(argv[optind], "security"))
2770+
if (arg_json_format_flags != JSON_FORMAT_OFF && !STRPTR_IN_SET(argv[optind], "security", "inspect-elf"))
27632771
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
27642772
"Option --json= is only supported for security right now.");
27652773

@@ -2835,6 +2843,7 @@ static int run(int argc, char *argv[]) {
28352843
{ "timestamp", 2, VERB_ANY, 0, test_timestamp },
28362844
{ "timespan", 2, VERB_ANY, 0, dump_timespan },
28372845
{ "security", VERB_ANY, VERB_ANY, 0, do_security },
2846+
{ "inspect-elf", 2, VERB_ANY, 0, do_elf_inspection },
28382847
{}
28392848
};
28402849

src/analyze/meson.build

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ systemd_analyze_sources = files('''
44
analyze.c
55
analyze-condition.c
66
analyze-condition.h
7+
analyze-elf.c
8+
analyze-elf.h
79
analyze-verify.c
810
analyze-verify.h
911
analyze-security.c

test/units/testsuite-65.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,10 @@ set -e
595595

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

598+
if systemd-analyze --version | grep -q -F "+ELFUTILS"; then
599+
systemd-analyze inspect-elf --json=short /lib/systemd/systemd | grep -q -F '"elfType":"executable"'
600+
fi
601+
598602
systemd-analyze log-level info
599603

600604
echo OK >/testok

0 commit comments

Comments
 (0)
X Tutup