condition: split condition_test_list() to minimize dlopen dependencies

Even though systemd-networkd and systemd-udevd do not support
ConditionSecurity= in .network, .netdev, and .link files, the unified
condition_test() function maintained a function pointer table that
unconditionally referenced condition_test_security(). Consequently,
linker garbage collection (--gc-sections) could not drop the security
test code, inadvertently pulling in dlopen dependencies and ELF notes
for apparmor, audit, and tpm2 libraries into these binaries.

To resolve this, introduce condition_test_net() and condition_test_list_net(),
which utilize a trimmed-down function pointer table that excludes
security-related condition evaluators.

By migrating networkd and udevd to these new network-specific variants,
the reference to condition_test_security() is completely severed in
their dependency chains. This allows the compiler and linker to
successfully garbage-collect the unused security logic and safely drops
the unnecessary dlopen notes from those binaries.
This commit is contained in:
Yu Watanabe
2026-07-10 16:35:19 +09:00
parent 05bdf4bfa9
commit 337f1a3195
7 changed files with 66 additions and 29 deletions
+1 -1
View File
@@ -1044,7 +1044,7 @@ int netdev_load_one(Manager *manager, const char *filename, NetDev **ret) {
return r; /* config_parse_many() logs internally. */
/* skip out early if configuration does not match the environment */
if (!condition_test_list(netdev_raw->conditions, environ, NULL, NULL, NULL))
if (!condition_test_list_net(netdev_raw->conditions, environ, NULL, NULL, NULL))
return log_debug_errno(SYNTHETIC_ERRNO(ESTALE), "%s: Conditions in the file do not match the system environment, skipping.", filename);
if (netdev_raw->kind == _NETDEV_KIND_INVALID)
+1 -1
View File
@@ -138,7 +138,7 @@ int network_verify(Network *network) {
network->filename);
/* skip out early if configuration does not match the environment */
if (!condition_test_list(network->conditions, environ, NULL, NULL, NULL))
if (!condition_test_list_net(network->conditions, environ, NULL, NULL, NULL))
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: Conditions in the file do not match the system environment, skipping.",
network->filename);
-5
View File
@@ -25,14 +25,9 @@ static int run(int argc, char *argv[]) {
_unused_ _cleanup_(notify_on_cleanup) const char *notify_message = NULL;
int r;
LIBAPPARMOR_NOTE(recommended);
LIBAUDIT_NOTE(recommended);
LIBIDN2_NOTE(suggested);
LIBMOUNT_NOTE(recommended);
LIBSELINUX_NOTE(recommended);
LIBTSS2_ESYS_NOTE(suggested);
LIBTSS2_MU_NOTE(suggested);
LIBTSS2_RC_NOTE(suggested);
log_setup();
+62 -19
View File
@@ -1340,9 +1340,45 @@ static int condition_test_kernel_module_loaded(Condition *c, char **env) {
return true;
}
int condition_test(Condition *c, char **env) {
typedef int (*condition_test_func_t)(Condition *c, char **env);
static int (*const condition_tests[_CONDITION_TYPE_MAX])(Condition *c, char **env) = {
static int condition_test_impl(Condition *c, char **env, const condition_test_func_t table[]) {
int r, b;
assert(c);
assert(c->type >= 0);
assert(c->type < _CONDITION_TYPE_MAX);
assert(table);
assert(table[c->type]);
r = table[c->type](c, env);
if (r < 0) {
c->result = CONDITION_ERROR;
return r;
}
b = (r > 0) == !c->negate;
c->result = b ? CONDITION_SUCCEEDED : CONDITION_FAILED;
return b;
}
static int condition_test_net(Condition *c, char **env) {
static const condition_test_func_t table_net[_CONDITION_TYPE_MAX] = {
[CONDITION_KERNEL_COMMAND_LINE] = condition_test_kernel_command_line,
[CONDITION_VERSION] = condition_test_version,
[CONDITION_CREDENTIAL] = condition_test_credential,
[CONDITION_VIRTUALIZATION] = condition_test_virtualization,
[CONDITION_HOST] = condition_test_host,
[CONDITION_ARCHITECTURE] = condition_test_architecture,
[CONDITION_FIRMWARE] = condition_test_firmware,
[CONDITION_MACHINE_TAG] = condition_test_machine_tag,
};
return condition_test_impl(c, env, table_net);
}
int condition_test(Condition *c, char **env) {
static const condition_test_func_t table[_CONDITION_TYPE_MAX] = {
[CONDITION_PATH_EXISTS] = condition_test_path_exists,
[CONDITION_PATH_EXISTS_GLOB] = condition_test_path_exists_glob,
[CONDITION_PATH_IS_DIRECTORY] = condition_test_path_is_directory,
@@ -1382,28 +1418,15 @@ int condition_test(Condition *c, char **env) {
[CONDITION_KERNEL_MODULE_LOADED] = condition_test_kernel_module_loaded,
};
int r, b;
assert(c);
assert(c->type >= 0);
assert(c->type < _CONDITION_TYPE_MAX);
r = condition_tests[c->type](c, env);
if (r < 0) {
c->result = CONDITION_ERROR;
return r;
}
b = (r > 0) == !c->negate;
c->result = b ? CONDITION_SUCCEEDED : CONDITION_FAILED;
return b;
return condition_test_impl(c, env, table);
}
bool condition_test_list(
static bool condition_test_list_impl(
Condition *first,
char **env,
condition_to_string_t to_string,
condition_test_logger_t logger,
condition_test_func_t tester,
void *userdata) {
int triggered = -1;
@@ -1418,7 +1441,7 @@ bool condition_test_list(
LIST_FOREACH(conditions, c, first) {
int r;
r = condition_test(c, env);
r = tester(c, env);
if (logger) {
if (r < 0)
@@ -1448,6 +1471,26 @@ bool condition_test_list(
return triggered != 0;
}
bool condition_test_list_net(
Condition *first,
char **env,
condition_to_string_t to_string,
condition_test_logger_t logger,
void *userdata) {
return condition_test_list_impl(first, env, to_string, logger, condition_test_net, userdata);
}
bool condition_test_list(
Condition *first,
char **env,
condition_to_string_t to_string,
condition_test_logger_t logger,
void *userdata) {
return condition_test_list_impl(first, env, to_string, logger, condition_test, userdata);
}
void condition_dump(Condition *c, FILE *f, const char *prefix, condition_to_string_t to_string) {
assert(c);
assert(f);
+1
View File
@@ -85,6 +85,7 @@ int condition_test(Condition *c, char **env);
typedef int (*condition_test_logger_t)(void *userdata, int level, int error, const char *file, int line, const char *func, const char *format, ...) _printf_(7, 8);
typedef const char* (*condition_to_string_t)(ConditionType t) _const_;
bool condition_test_list_net(Condition *first, char **env, condition_to_string_t to_string, condition_test_logger_t logger, void *userdata);
bool condition_test_list(Condition *first, char **env, condition_to_string_t to_string, condition_test_logger_t logger, void *userdata);
void condition_dump(Condition *c, FILE *f, const char *prefix, condition_to_string_t to_string);
+1 -1
View File
@@ -320,7 +320,7 @@ int link_load_one(LinkConfigContext *ctx, const char *filename) {
return 0;
}
if (!condition_test_list(config->conditions, environ, NULL, NULL, NULL)) {
if (!condition_test_list_net(config->conditions, environ, NULL, NULL, NULL)) {
log_debug("%s: Conditions do not match the system environment, skipping.", filename);
return 0;
}
-2
View File
@@ -102,8 +102,6 @@ static int run(int argc, char *argv[]) {
char **args = NULL;
int r;
LIBAPPARMOR_NOTE(recommended);
LIBAUDIT_NOTE(recommended);
LIBSELINUX_NOTE(recommended);
if (invoked_as(argv, "udevd"))