analyze: Add dlopen-metadata verb (#39457)
systemd-analyze dlopen-metadata will show dlopen metadata in the ELF binary.
This commit is contained in:
@@ -915,6 +915,16 @@ alias.service:7: Unknown key name 'MysteryKey' in section 'Service', ignoring.
|
||||
</example>
|
||||
</refsect2>
|
||||
|
||||
<refsect2>
|
||||
<title><command>systemd-analyze dlopen-metadata <replaceable>FILE</replaceable></command></title>
|
||||
|
||||
<para>This command will load the specified file, and if it is an ELF object (executables,
|
||||
libraries, core files, etc.) it will parse the embedded dlopen metadata, if any, and print
|
||||
it in a table or json format. See the
|
||||
<ulink url="https://systemd.io/ELF_DLOPEN_METADATA/">
|
||||
dlopen() Metadata for ELF Files</ulink> document for more information.</para>
|
||||
</refsect2>
|
||||
|
||||
<refsect2>
|
||||
<title><command>systemd-analyze fdstore <replaceable>UNIT</replaceable>...</command></title>
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "sd-json.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "analyze.h"
|
||||
#include "analyze-dlopen-metadata.h"
|
||||
#include "chase.h"
|
||||
#include "elf-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "format-table.h"
|
||||
#include "json-util.h"
|
||||
#include "strv.h"
|
||||
|
||||
int verb_dlopen_metadata(int argc, char *argv[], void *userdata) {
|
||||
int r;
|
||||
|
||||
_cleanup_free_ char *abspath = NULL;
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
fd = chase_and_open(argv[1], arg_root, CHASE_PREFIX_ROOT, O_RDONLY|O_CLOEXEC, &abspath);
|
||||
if (fd < 0)
|
||||
return log_error_errno(fd, "Could not open \"%s\": %m", argv[1]);
|
||||
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *dlopen_metadata = NULL;
|
||||
r = parse_elf_object(
|
||||
fd,
|
||||
abspath,
|
||||
arg_root,
|
||||
/* fork_disable_dump= */ false,
|
||||
/* ret= */ NULL,
|
||||
NULL,
|
||||
&dlopen_metadata);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Parsing \"%s\" as ELF object failed: %m", abspath);
|
||||
|
||||
if (!dlopen_metadata)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENODATA), "%s does not contain any .note.dlopen sections", argv[1]);
|
||||
|
||||
if (sd_json_format_enabled(arg_json_format_flags))
|
||||
return sd_json_variant_dump(dlopen_metadata, arg_json_format_flags, stdout, NULL);
|
||||
|
||||
_cleanup_(table_unrefp) Table *t = NULL;
|
||||
t = table_new("feature", "description", "soname", "priority");
|
||||
if (!t)
|
||||
return log_oom();
|
||||
|
||||
table_set_ersatz_string(t, TABLE_ERSATZ_NA);
|
||||
|
||||
sd_json_variant *z;
|
||||
JSON_VARIANT_ARRAY_FOREACH(z, dlopen_metadata) {
|
||||
_cleanup_strv_free_ char **sonames = NULL;
|
||||
|
||||
r = sd_json_variant_strv(sd_json_variant_by_key(z, "soname"), &sonames);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to extract sonames from dlopen metadata: %m");
|
||||
|
||||
r = table_add_many(
|
||||
t,
|
||||
TABLE_STRING, sd_json_variant_string(sd_json_variant_by_key(z, "feature")),
|
||||
TABLE_STRING, sd_json_variant_string(sd_json_variant_by_key(z, "description")),
|
||||
TABLE_STRV_WRAPPED, sonames,
|
||||
TABLE_STRING, sd_json_variant_string(sd_json_variant_by_key(z, "priority")));
|
||||
if (r < 0)
|
||||
return table_log_add_error(r);
|
||||
}
|
||||
|
||||
r = table_print(t, NULL);
|
||||
if (r < 0)
|
||||
return table_log_print_error(r);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
int verb_dlopen_metadata(int argc, char *argv[], void *userdata);
|
||||
@@ -27,7 +27,14 @@ static int analyze_elf(char **filenames, sd_json_format_flags_t json_flags) {
|
||||
if (fd < 0)
|
||||
return log_error_errno(fd, "Could not open \"%s\": %m", *filename);
|
||||
|
||||
r = parse_elf_object(fd, abspath, arg_root, /* fork_disable_dump= */false, &stacktrace, &package_metadata);
|
||||
r = parse_elf_object(
|
||||
fd,
|
||||
abspath,
|
||||
arg_root,
|
||||
/* fork_disable_dump= */ false,
|
||||
&stacktrace,
|
||||
&package_metadata,
|
||||
/* ret_dlopen_metadata= */ NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Parsing \"%s\" as ELF object failed: %m", abspath);
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "analyze-compare-versions.h"
|
||||
#include "analyze-condition.h"
|
||||
#include "analyze-critical-chain.h"
|
||||
#include "analyze-dlopen-metadata.h"
|
||||
#include "analyze-dot.h"
|
||||
#include "analyze-dump.h"
|
||||
#include "analyze-exit-status.h"
|
||||
@@ -798,6 +799,7 @@ static int run(int argc, char *argv[]) {
|
||||
{ "timespan", 2, VERB_ANY, 0, verb_timespan },
|
||||
{ "security", VERB_ANY, VERB_ANY, 0, verb_security },
|
||||
{ "inspect-elf", 2, VERB_ANY, 0, verb_elf_inspection },
|
||||
{ "dlopen-metadata", 2, 2, 0, verb_dlopen_metadata },
|
||||
{ "malloc", VERB_ANY, VERB_ANY, 0, verb_malloc },
|
||||
{ "fdstore", 2, VERB_ANY, 0, verb_fdstore },
|
||||
{ "image-policy", 2, 2, 0, verb_image_policy },
|
||||
|
||||
@@ -10,6 +10,7 @@ systemd_analyze_sources = files(
|
||||
'analyze-compare-versions.c',
|
||||
'analyze-condition.c',
|
||||
'analyze-critical-chain.c',
|
||||
'analyze-dlopen-metadata.c',
|
||||
'analyze-dot.c',
|
||||
'analyze-dump.c',
|
||||
'analyze-exit-status.c',
|
||||
|
||||
@@ -689,7 +689,8 @@ int coredump_submit(
|
||||
root,
|
||||
/* fork_disable_dump= */ skip, /* avoid loops */
|
||||
&stacktrace,
|
||||
&json_metadata);
|
||||
&json_metadata,
|
||||
/* ret_dlopen_metadata= */ NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+131
-47
@@ -20,6 +20,7 @@
|
||||
#include "fileio.h"
|
||||
#include "format-util.h"
|
||||
#include "io-util.h"
|
||||
#include "json-util.h"
|
||||
#include "log.h"
|
||||
#include "memstream-util.h"
|
||||
#include "path-util.h"
|
||||
@@ -186,6 +187,7 @@ typedef struct StackContext {
|
||||
unsigned n_thread;
|
||||
unsigned n_frame;
|
||||
sd_json_variant **package_metadata;
|
||||
sd_json_variant **dlopen_metadata;
|
||||
Set **modules;
|
||||
} StackContext;
|
||||
|
||||
@@ -352,8 +354,8 @@ static void report_module_metadata(StackContext *c, const char *name, sd_json_va
|
||||
fputs("\n", c->m.f);
|
||||
}
|
||||
|
||||
static int parse_package_metadata(const char *name, sd_json_variant *id_json, Elf *elf, bool *ret_interpreter_found, StackContext *c) {
|
||||
bool interpreter_found = false;
|
||||
static int parse_metadata(const char *name, sd_json_variant *id_json, Elf *elf, bool *ret_interpreter_found, StackContext *c) {
|
||||
bool package_metadata_found = false, interpreter_found = false;
|
||||
size_t n_program_headers;
|
||||
int r;
|
||||
|
||||
@@ -408,7 +410,7 @@ static int parse_package_metadata(const char *name, sd_json_variant *id_json, El
|
||||
|
||||
/* Package metadata might have different owners, but the
|
||||
* magic ID is always the same. */
|
||||
if (note_header.n_type != ELF_PACKAGE_METADATA_ID)
|
||||
if (!IN_SET(note_header.n_type, ELF_PACKAGE_METADATA_ID, ELF_NOTE_DLOPEN_TYPE))
|
||||
continue;
|
||||
|
||||
_cleanup_free_ char *payload_0suffixed = NULL;
|
||||
@@ -430,46 +432,59 @@ static int parse_package_metadata(const char *name, sd_json_variant *id_json, El
|
||||
return log_error_errno(r, "json_parse on \"%s\" failed: %m", strnull(esc));
|
||||
}
|
||||
|
||||
/* If we have a build-id, merge it in the same JSON object so that it appears all
|
||||
* nicely together in the logs/metadata. */
|
||||
if (id_json) {
|
||||
r = sd_json_variant_merge_object(&v, id_json);
|
||||
if (note_header.n_type == ELF_PACKAGE_METADATA_ID) {
|
||||
/* If we have a build-id, merge it in the same JSON object so that it appears all
|
||||
* nicely together in the logs/metadata. */
|
||||
if (id_json) {
|
||||
r = sd_json_variant_merge_object(&v, id_json);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "sd_json_variant_merge of package meta with buildId failed: %m");
|
||||
}
|
||||
|
||||
/* Pretty-print to the buffer, so that the metadata goes as plaintext in the
|
||||
* journal. */
|
||||
report_module_metadata(c, name, v);
|
||||
|
||||
/* Then we build a new object using the module name as the key, and merge it
|
||||
* with the previous parses, so that in the end it all fits together in a single
|
||||
* JSON blob. */
|
||||
r = sd_json_buildo(&w, SD_JSON_BUILD_PAIR(name, SD_JSON_BUILD_VARIANT(v)));
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to build JSON object: %m");
|
||||
|
||||
r = sd_json_variant_merge_object(c->package_metadata, w);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "sd_json_variant_merge of package meta with buildId failed: %m");
|
||||
|
||||
package_metadata_found = true;
|
||||
} else if (c->dlopen_metadata) {
|
||||
sd_json_variant *z;
|
||||
|
||||
JSON_VARIANT_ARRAY_FOREACH(z, v) {
|
||||
r = sd_json_variant_append_array(c->dlopen_metadata, z);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to append entry to dlopen metadata: %m");
|
||||
}
|
||||
}
|
||||
|
||||
/* Pretty-print to the buffer, so that the metadata goes as plaintext in the
|
||||
* journal. */
|
||||
report_module_metadata(c, name, v);
|
||||
|
||||
/* Then we build a new object using the module name as the key, and merge it
|
||||
* with the previous parses, so that in the end it all fits together in a single
|
||||
* JSON blob. */
|
||||
r = sd_json_buildo(&w, SD_JSON_BUILD_PAIR(name, SD_JSON_BUILD_VARIANT(v)));
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to build JSON object: %m");
|
||||
|
||||
r = sd_json_variant_merge_object(c->package_metadata, w);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "sd_json_variant_merge of package meta with buildId failed: %m");
|
||||
|
||||
/* Finally stash the name, so we avoid double visits. */
|
||||
r = set_put_strdup(c->modules, name);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "set_put_strdup failed: %m");
|
||||
|
||||
if (ret_interpreter_found)
|
||||
*ret_interpreter_found = interpreter_found;
|
||||
if (!c->dlopen_metadata) {
|
||||
if (ret_interpreter_found)
|
||||
*ret_interpreter_found = interpreter_found;
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ret_interpreter_found)
|
||||
*ret_interpreter_found = interpreter_found;
|
||||
|
||||
/* Didn't find package metadata for this module - that's ok, just go to the next. */
|
||||
return 0;
|
||||
return c->dlopen_metadata ? 0 : package_metadata_found;
|
||||
}
|
||||
|
||||
/* Get the build-id out of an ELF object or a dwarf core module. */
|
||||
@@ -535,7 +550,7 @@ static int module_callback(Dwfl_Module *mod, void **userdata, const char *name,
|
||||
* to the ELF object first. We might be lucky and just get it from elfutils. */
|
||||
elf = sym_dwfl_module_getelf(mod, &bias);
|
||||
if (elf) {
|
||||
r = parse_package_metadata(name, id_json, elf, NULL, c);
|
||||
r = parse_metadata(name, id_json, elf, NULL, c);
|
||||
if (r < 0)
|
||||
return DWARF_CB_ABORT;
|
||||
if (r > 0)
|
||||
@@ -590,7 +605,8 @@ static int module_callback(Dwfl_Module *mod, void **userdata, const char *name,
|
||||
_cleanup_(elf_endp) Elf *memelf = sym_elf_memory(data->d_buf, data->d_size);
|
||||
if (!memelf)
|
||||
continue;
|
||||
r = parse_package_metadata(name, id_json, memelf, NULL, c);
|
||||
|
||||
r = parse_metadata(name, id_json, memelf, NULL, c);
|
||||
if (r < 0)
|
||||
return DWARF_CB_ABORT;
|
||||
if (r > 0)
|
||||
@@ -600,7 +616,12 @@ static int module_callback(Dwfl_Module *mod, void **userdata, const char *name,
|
||||
return DWARF_CB_OK;
|
||||
}
|
||||
|
||||
static int parse_core(int fd, const char *root, char **ret, sd_json_variant **ret_package_metadata) {
|
||||
static int parse_core(
|
||||
int fd,
|
||||
const char *root,
|
||||
char **ret,
|
||||
sd_json_variant **ret_package_metadata,
|
||||
sd_json_variant **ret_dlopen_metadata) {
|
||||
|
||||
const Dwfl_Callbacks callbacks = {
|
||||
.find_elf = sym_dwfl_build_id_find_elf,
|
||||
@@ -608,10 +629,11 @@ static int parse_core(int fd, const char *root, char **ret, sd_json_variant **re
|
||||
.find_debuginfo = sym_dwfl_standard_find_debuginfo,
|
||||
};
|
||||
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *package_metadata = NULL;
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *package_metadata = NULL, *dlopen_metadata = NULL;
|
||||
_cleanup_set_free_ Set *modules = NULL;
|
||||
_cleanup_(stack_context_done) StackContext c = {
|
||||
.package_metadata = &package_metadata,
|
||||
.dlopen_metadata = ret_dlopen_metadata ? &dlopen_metadata : NULL,
|
||||
.modules = &modules,
|
||||
};
|
||||
int r;
|
||||
@@ -667,15 +689,24 @@ static int parse_core(int fd, const char *root, char **ret, sd_json_variant **re
|
||||
|
||||
if (ret_package_metadata)
|
||||
*ret_package_metadata = TAKE_PTR(package_metadata);
|
||||
if (ret_dlopen_metadata)
|
||||
*ret_dlopen_metadata = TAKE_PTR(dlopen_metadata);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_elf(int fd, const char *executable, const char *root, char **ret, sd_json_variant **ret_package_metadata) {
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *package_metadata = NULL, *elf_metadata = NULL;
|
||||
static int parse_elf(
|
||||
int fd,
|
||||
const char *executable,
|
||||
const char *root,
|
||||
char **ret,
|
||||
sd_json_variant **ret_package_metadata,
|
||||
sd_json_variant **ret_dlopen_metadata) {
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *package_metadata = NULL, *dlopen_metadata = NULL, *elf_metadata = NULL;
|
||||
_cleanup_set_free_ Set *modules = NULL;
|
||||
_cleanup_(stack_context_done) StackContext c = {
|
||||
.package_metadata = &package_metadata,
|
||||
.dlopen_metadata = ret_dlopen_metadata ? &dlopen_metadata : NULL,
|
||||
.modules = &modules,
|
||||
};
|
||||
const char *elf_type;
|
||||
@@ -702,7 +733,7 @@ static int parse_elf(int fd, const char *executable, const char *root, char **re
|
||||
if (elf_header.e_type == ET_CORE) {
|
||||
_cleanup_free_ char *out = NULL;
|
||||
|
||||
r = parse_core(fd, root, ret ? &out : NULL, &package_metadata);
|
||||
r = parse_core(fd, root, ret ? &out : NULL, &package_metadata, &dlopen_metadata);
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "Failed to inspect core file: %m");
|
||||
|
||||
@@ -719,7 +750,7 @@ static int parse_elf(int fd, const char *executable, const char *root, char **re
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "Failed to parse build-id of ELF file: %m");
|
||||
|
||||
r = parse_package_metadata(e, id_json, c.elf, &interpreter_found, &c);
|
||||
r = parse_metadata(e, id_json, c.elf, &interpreter_found, &c);
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "Failed to parse package metadata of ELF file: %m");
|
||||
|
||||
@@ -769,18 +800,28 @@ static int parse_elf(int fd, const char *executable, const char *root, char **re
|
||||
|
||||
if (ret_package_metadata)
|
||||
*ret_package_metadata = TAKE_PTR(elf_metadata);
|
||||
if (ret_dlopen_metadata)
|
||||
*ret_dlopen_metadata = TAKE_PTR(dlopen_metadata);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int parse_elf_object(int fd, const char *executable, const char *root, bool fork_disable_dump, char **ret, sd_json_variant **ret_package_metadata) {
|
||||
int parse_elf_object(
|
||||
int fd,
|
||||
const char *executable,
|
||||
const char *root,
|
||||
bool fork_disable_dump,
|
||||
char **ret,
|
||||
sd_json_variant **ret_package_metadata,
|
||||
sd_json_variant **ret_dlopen_metadata) {
|
||||
#if HAVE_ELFUTILS
|
||||
_cleanup_close_pair_ int error_pipe[2] = EBADF_PAIR,
|
||||
return_pipe[2] = EBADF_PAIR,
|
||||
json_pipe[2] = EBADF_PAIR;
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *package_metadata = NULL;
|
||||
package_metadata_pipe[2] = EBADF_PAIR,
|
||||
dlopen_metadata_pipe[2] = EBADF_PAIR;
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *package_metadata = NULL, *dlopen_metadata = NULL;
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
int r;
|
||||
|
||||
@@ -805,7 +846,13 @@ int parse_elf_object(int fd, const char *executable, const char *root, bool fork
|
||||
}
|
||||
|
||||
if (ret_package_metadata) {
|
||||
r = RET_NERRNO(pipe2(json_pipe, O_CLOEXEC|O_NONBLOCK));
|
||||
r = RET_NERRNO(pipe2(package_metadata_pipe, O_CLOEXEC|O_NONBLOCK));
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (ret_dlopen_metadata) {
|
||||
r = RET_NERRNO(pipe2(dlopen_metadata_pipe, O_CLOEXEC|O_NONBLOCK));
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
@@ -818,8 +865,8 @@ int parse_elf_object(int fd, const char *executable, const char *root, bool fork
|
||||
* the file descriptor and writing into these four pipes. */
|
||||
r = safe_fork_full("(sd-parse-elf)",
|
||||
NULL,
|
||||
(int[]){ fd, error_pipe[1], return_pipe[1], json_pipe[1] },
|
||||
4,
|
||||
(int[]){ fd, error_pipe[1], return_pipe[1], package_metadata_pipe[1], dlopen_metadata_pipe[1] },
|
||||
5,
|
||||
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_NEW_MOUNTNS|FORK_MOUNTNS_SLAVE|FORK_NEW_USERNS|FORK_WAIT|FORK_REOPEN_LOG,
|
||||
NULL);
|
||||
if (r < 0) {
|
||||
@@ -846,7 +893,13 @@ int parse_elf_object(int fd, const char *executable, const char *root, bool fork
|
||||
report_errno_and_exit(error_pipe[1], r);
|
||||
}
|
||||
|
||||
r = parse_elf(fd, executable, root, ret ? &buf : NULL, ret_package_metadata ? &package_metadata : NULL);
|
||||
r = parse_elf(
|
||||
fd,
|
||||
executable,
|
||||
root,
|
||||
ret ? &buf : NULL,
|
||||
ret_package_metadata ? &package_metadata : NULL,
|
||||
ret_dlopen_metadata ? &dlopen_metadata : NULL);
|
||||
if (r < 0)
|
||||
report_errno_and_exit(error_pipe[1], r);
|
||||
|
||||
@@ -879,9 +932,9 @@ int parse_elf_object(int fd, const char *executable, const char *root, bool fork
|
||||
|
||||
/* Bump the space for the returned string. We don't know how much space we'll need in
|
||||
* advance, so we'll just try to write as much as possible and maybe fail later. */
|
||||
(void) fcntl(json_pipe[1], F_SETPIPE_SZ, COREDUMP_PIPE_MAX);
|
||||
(void) fcntl(package_metadata_pipe[1], F_SETPIPE_SZ, COREDUMP_PIPE_MAX);
|
||||
|
||||
json_out = take_fdopen(&json_pipe[1], "w");
|
||||
json_out = take_fdopen(&package_metadata_pipe[1], "w");
|
||||
if (!json_out)
|
||||
report_errno_and_exit(error_pipe[1], -errno);
|
||||
|
||||
@@ -890,12 +943,29 @@ int parse_elf_object(int fd, const char *executable, const char *root, bool fork
|
||||
log_warning_errno(r, "Failed to write JSON package metadata, ignoring: %m");
|
||||
}
|
||||
|
||||
if (dlopen_metadata) {
|
||||
_cleanup_fclose_ FILE *json_out = NULL;
|
||||
|
||||
/* Bump the space for the returned string. We don't know how much space we'll need in
|
||||
* advance, so we'll just try to write as much as possible and maybe fail later. */
|
||||
(void) fcntl(dlopen_metadata_pipe[1], F_SETPIPE_SZ, COREDUMP_PIPE_MAX);
|
||||
|
||||
json_out = take_fdopen(&dlopen_metadata_pipe[1], "w");
|
||||
if (!json_out)
|
||||
report_errno_and_exit(error_pipe[1], -errno);
|
||||
|
||||
r = sd_json_variant_dump(dlopen_metadata, SD_JSON_FORMAT_FLUSH, json_out, NULL);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to write JSON package metadata, ignoring: %m");
|
||||
}
|
||||
|
||||
_exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
error_pipe[1] = safe_close(error_pipe[1]);
|
||||
return_pipe[1] = safe_close(return_pipe[1]);
|
||||
json_pipe[1] = safe_close(json_pipe[1]);
|
||||
package_metadata_pipe[1] = safe_close(package_metadata_pipe[1]);
|
||||
dlopen_metadata_pipe[1] = safe_close(dlopen_metadata_pipe[1]);
|
||||
|
||||
if (ret) {
|
||||
_cleanup_fclose_ FILE *in = NULL;
|
||||
@@ -912,19 +982,33 @@ int parse_elf_object(int fd, const char *executable, const char *root, bool fork
|
||||
if (ret_package_metadata) {
|
||||
_cleanup_fclose_ FILE *json_in = NULL;
|
||||
|
||||
json_in = take_fdopen(&json_pipe[0], "r");
|
||||
json_in = take_fdopen(&package_metadata_pipe[0], "r");
|
||||
if (!json_in)
|
||||
return -errno;
|
||||
|
||||
r = sd_json_parse_file(json_in, NULL, 0, &package_metadata, NULL, NULL);
|
||||
if (r < 0 && r != -ENODATA) /* ENODATA: json was empty, so we got nothing, but that's ok */
|
||||
log_warning_errno(r, "Failed to read or parse json metadata, ignoring: %m");
|
||||
log_warning_errno(r, "Failed to read or parse package metadata, ignoring: %m");
|
||||
}
|
||||
|
||||
if (ret_dlopen_metadata) {
|
||||
_cleanup_fclose_ FILE *json_in = NULL;
|
||||
|
||||
json_in = take_fdopen(&dlopen_metadata_pipe[0], "r");
|
||||
if (!json_in)
|
||||
return -errno;
|
||||
|
||||
r = sd_json_parse_file(json_in, NULL, 0, &dlopen_metadata, NULL, NULL);
|
||||
if (r < 0 && r != -ENODATA) /* ENODATA: json was empty, so we got nothing, but that's ok */
|
||||
log_warning_errno(r, "Failed to read or parse dlopen metadata, ignoring: %m");
|
||||
}
|
||||
|
||||
if (ret)
|
||||
*ret = TAKE_PTR(buf);
|
||||
if (ret_package_metadata)
|
||||
*ret_package_metadata = TAKE_PTR(package_metadata);
|
||||
if (ret_dlopen_metadata)
|
||||
*ret_dlopen_metadata = TAKE_PTR(dlopen_metadata);
|
||||
|
||||
return 0;
|
||||
#else
|
||||
|
||||
@@ -9,4 +9,11 @@ int dlopen_elf(void);
|
||||
/* Parse an ELF object in a forked process, so that errors while iterating over
|
||||
* untrusted and potentially malicious data do not propagate to the main caller's process.
|
||||
* If fork_disable_dump, the child process will not dump core if it crashes. */
|
||||
int parse_elf_object(int fd, const char *executable, const char *root, bool fork_disable_dump, char **ret, sd_json_variant **ret_package_metadata);
|
||||
int parse_elf_object(
|
||||
int fd,
|
||||
const char *executable,
|
||||
const char *root,
|
||||
bool fork_disable_dump,
|
||||
char **ret,
|
||||
sd_json_variant **ret_package_metadata,
|
||||
sd_json_variant **ret_dlopen_metadata);
|
||||
|
||||
@@ -18,7 +18,7 @@ systemd-analyze time || :
|
||||
systemd-analyze critical-chain || :
|
||||
# blame
|
||||
systemd-analyze blame
|
||||
systemd-run --wait --user --pipe -M testuser@.host systemd-analyze blame
|
||||
systemd-run --wait --user --pipe -M testuser@.host systemd-analyze blame --no-pager
|
||||
(! systemd-analyze blame --global)
|
||||
# plot
|
||||
systemd-analyze plot >/dev/null || :
|
||||
@@ -1006,7 +1006,16 @@ systemd-analyze security --threshold=25 --offline=true \
|
||||
rm /tmp/img/usr/lib/systemd/system/testfile.service
|
||||
|
||||
if systemd-analyze --version | grep -q -F "+ELFUTILS"; then
|
||||
systemd-analyze inspect-elf /lib/systemd/systemd
|
||||
systemd-analyze inspect-elf --json=short /lib/systemd/systemd | grep -q -F '"elfType":"executable"'
|
||||
|
||||
# For some unknown reason the .note.dlopen sections are removed when building with sanitizers, so only
|
||||
# run this test if we're not running under sanitizers.
|
||||
if [[ ! -v ASAN_OPTIONS ]]; then
|
||||
shared="$(ldd /lib/systemd/systemd | grep shared | cut -d' ' -f3)"
|
||||
systemd-analyze dlopen-metadata "$shared"
|
||||
systemd-analyze dlopen-metadata --json=short "$shared"
|
||||
fi
|
||||
fi
|
||||
|
||||
systemd-analyze --threshold=90 security systemd-journald.service
|
||||
|
||||
Reference in New Issue
Block a user