summaryrefslogtreecommitdiff
path: root/src/analyze
diff options
context:
space:
mode:
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2021-12-06 12:45:25 +0100
committerGitHub <noreply@github.com>2021-12-06 12:45:25 +0100
commitec1574cd8ed6a7ca3386eca61aae92ce989b1f05 (patch)
tree35a978b6978bba6f1e2b8e8a8c1a958cb6c2b42a /src/analyze
parent2f121b6fa1f6aa4c9bd699fce52f0b087abefd01 (diff)
parent917e655457cb2e0730d4c7baf4b65cd26986f663 (diff)
downloadsystemd-ec1574cd8ed6a7ca3386eca61aae92ce989b1f05.tar.gz
Merge pull request #21454 from bluca/inspect_elf
analyze: add inspect-elf verb to parse package metadata
Diffstat (limited to 'src/analyze')
-rw-r--r--src/analyze/analyze-elf.c128
-rw-r--r--src/analyze/analyze-elf.h6
-rw-r--r--src/analyze/analyze.c11
-rw-r--r--src/analyze/meson.build2
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 d5057bbe85..2293fcea6a 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