diff options
author | Luca Boccassi <luca.boccassi@microsoft.com> | 2021-11-17 01:45:07 +0000 |
---|---|---|
committer | Luca Boccassi <luca.boccassi@microsoft.com> | 2021-11-30 23:14:07 +0000 |
commit | 917e655457cb2e0730d4c7baf4b65cd26986f663 (patch) | |
tree | d845a49279fd121029469fc3955cc7006929f0f6 /src/analyze | |
parent | d48c2721b6b94a7aae470dcfcdc0578c971dc556 (diff) | |
download | systemd-917e655457cb2e0730d4c7baf4b65cd26986f663.tar.gz |
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"
}
Diffstat (limited to 'src/analyze')
-rw-r--r-- | src/analyze/analyze-elf.c | 128 | ||||
-rw-r--r-- | src/analyze/analyze-elf.h | 6 | ||||
-rw-r--r-- | src/analyze/analyze.c | 11 | ||||
-rw-r--r-- | src/analyze/meson.build | 2 |
4 files changed, 146 insertions, 1 deletions
diff --git a/src/analyze/analyze-elf.c b/src/analyze/analyze-elf.c new file mode 100644 index 0000000000..741cd20f99 --- /dev/null +++ b/src/analyze/analyze-elf.c @@ -0,0 +1,128 @@ +/* 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, /* fork_disable_dump= */false, NULL, &package_metadata); + if (r < 0) + return log_error_errno(r, "Parsing \"%s\" as ELF object failed: %m", abspath); + + t = table_new("", ""); + if (!t) + return log_oom(); + + r = table_set_align_percent(t, TABLE_HEADER_CELL(0), 100); + if (r < 0) + return table_log_add_error(r); + + r = table_add_many( + t, + TABLE_STRING, "path:", + TABLE_STRING, abspath); + if (r < 0) + return table_log_add_error(r); + + if (package_metadata) { + JsonVariant *module_json; + const char *module_name; + + JSON_VARIANT_OBJECT_FOREACH(module_name, module_json, package_metadata) { + const char *field_name; + JsonVariant *field; + + /* The ELF type and architecture are added as top-level objects, + * since they are only parsed for the file itself, but the packaging + * metadata is parsed recursively in core files, so there might be + * multiple modules. */ + if (STR_IN_SET(module_name, "elfType", "elfArchitecture")) { + _cleanup_free_ char *suffixed = NULL; + + suffixed = strjoin(module_name, ":"); + if (!suffixed) + return log_oom(); + + r = table_add_many( + t, + TABLE_STRING, suffixed, + TABLE_STRING, json_variant_string(module_json)); + if (r < 0) + return table_log_add_error(r); + + continue; + } + + /* path/elfType/elfArchitecture come first just once per file, + * then we might have multiple modules, so add a separator between + * them to make the output more readable. */ + r = table_add_many(t, TABLE_EMPTY, TABLE_EMPTY); + if (r < 0) + return table_log_add_error(r); + + /* 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)) { + _cleanup_free_ char *suffixed = NULL; + + suffixed = strjoin(field_name, ":"); + if (!suffixed) + return log_oom(); + + r = table_add_many( + t, + TABLE_STRING, suffixed, + 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; +} diff --git a/src/analyze/analyze-elf.h b/src/analyze/analyze-elf.h new file mode 100644 index 0000000000..e0d4712e5a --- /dev/null +++ b/src/analyze/analyze-elf.h @@ -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); diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c index a641be4179..dfbfda6009 100644 --- a/src/analyze/analyze.c +++ b/src/analyze/analyze.c @@ -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" @@ -2431,6 +2432,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; @@ -2473,6 +2480,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" @@ -2759,7 +2767,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."); @@ -2835,6 +2843,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 }, {} }; diff --git a/src/analyze/meson.build b/src/analyze/meson.build index f796629cc2..492b79069f 100644 --- a/src/analyze/meson.build +++ b/src/analyze/meson.build @@ -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 |