1
0
mirror of https://github.com/systemd/systemd synced 2026-03-30 11:44:49 +02:00

Compare commits

..

No commits in common. "c6c43d677abe66c404a2fb4aa66707bcabff4dff" and "6077791b3a2cdcd92c369f70f730e5b2c3e8274b" have entirely different histories.

13 changed files with 56 additions and 393 deletions

View File

@ -15,7 +15,7 @@ project('systemd', 'c',
add_test_setup( add_test_setup(
'default', 'default',
exclude_suites : ['clang-tidy', 'unused-symbols', 'integration-tests'], exclude_suites : ['clang-tidy', 'integration-tests'],
is_default : true, is_default : true,
) )
@ -2227,7 +2227,7 @@ libudev = shared_library(
implicit_include_directories : false, implicit_include_directories : false,
link_args : ['-shared', link_args : ['-shared',
'-Wl,--version-script=' + libudev_sym_path], '-Wl,--version-script=' + libudev_sym_path],
link_with : [libsystemd_static], link_with : [libsystemd_static, libshared_static],
link_whole : libudev_basic, link_whole : libudev_basic,
dependencies : [threads, dependencies : [threads,
userspace], userspace],
@ -3000,19 +3000,6 @@ if meson.version().version_compare('>=1.4.0')
endforeach endforeach
endif endif
symbol_analysis_exes = []
foreach name, exe : executables_by_name
symbol_analysis_exes += exe
endforeach
find_unused_library_symbols = find_program('tools/find-unused-library-symbols.py')
test(
'libshared-unused-symbols',
find_unused_library_symbols,
suite : 'unused-symbols',
args : [libshared, libcore] + nss_targets + pam_targets + symbol_analysis_exes,
)
run_target( run_target(
'check-api-docs', 'check-api-docs',
depends : [man, libsystemd, libudev], depends : [man, libsystemd, libudev],

View File

@ -23,7 +23,6 @@ basic_sources = files(
'compress.c', 'compress.c',
'conf-files.c', 'conf-files.c',
'confidential-virt.c', 'confidential-virt.c',
'device-nodes.c',
'devnum-util.c', 'devnum-util.c',
'dirent-util.c', 'dirent-util.c',
'dlfcn-util.c', 'dlfcn-util.c',

View File

@ -1233,7 +1233,7 @@ static int measured_crypt_activate_by_passphrase(
if (keyslot < 0) if (keyslot < 0)
return keyslot; return keyslot;
return measured_crypt_activate_by_volume_key(cd, name, mechanism, keyslot, vk, vks, flags); return measured_crypt_activate_by_volume_key(cd, mechanism, name, keyslot, vk, vks, flags);
shortcut: shortcut:
keyslot = crypt_activate_by_passphrase(cd, name, keyslot, passphrase, passphrase_size, flags); keyslot = crypt_activate_by_passphrase(cd, name, keyslot, passphrase, passphrase_size, flags);

View File

@ -12,6 +12,7 @@
#include "errno-util.h" #include "errno-util.h"
#include "fd-util.h" #include "fd-util.h"
#include "io-util.h" #include "io-util.h"
#include "udev-util.h"
/** /**
* SECTION:libudev-queue * SECTION:libudev-queue
@ -63,11 +64,6 @@ static struct udev_queue* udev_queue_free(struct udev_queue *udev_queue) {
return mfree(udev_queue); return mfree(udev_queue);
} }
static int udev_queue_is_empty(void) {
return access("/run/udev/queue", F_OK) < 0 ?
(errno == ENOENT ? true : -errno) : false;
}
/** /**
* udev_queue_ref: * udev_queue_ref:
* @udev_queue: udev queue context * @udev_queue: udev queue context

View File

@ -1,7 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once #pragma once
#include "basic-forward.h" #include "shared-forward.h"
int encode_devnode_name(const char *str, char *str_enc, size_t len); int encode_devnode_name(const char *str, char *str_enc, size_t len);
int allow_listed_char_for_devnode(char c, const char *additional); int allow_listed_char_for_devnode(char c, const char *additional);

View File

@ -57,6 +57,7 @@ shared_sources = files(
'daemon-util.c', 'daemon-util.c',
'data-fd-util.c', 'data-fd-util.c',
'dev-setup.c', 'dev-setup.c',
'device-nodes.c',
'discover-image.c', 'discover-image.c',
'dissect-image.c', 'dissect-image.c',
'dm-util.c', 'dm-util.c',

View File

@ -3,26 +3,15 @@
executables += [ executables += [
generator_template + { generator_template + {
'name' : 'systemd-ssh-generator', 'name' : 'systemd-ssh-generator',
'sources' : files( 'sources' : files('ssh-generator.c'),
'ssh-generator.c',
'ssh-util.c',
),
'extract' : files(
'ssh-util.c',
),
}, },
libexec_template + { libexec_template + {
'name' : 'systemd-ssh-proxy', 'name' : 'systemd-ssh-proxy',
'sources' : files( 'sources' : files('ssh-proxy.c'),
'ssh-proxy.c',
),
}, },
libexec_template + { libexec_template + {
'name' : 'systemd-ssh-issue', 'name' : 'systemd-ssh-issue',
'sources' : files( 'sources' : files('ssh-issue.c'),
'ssh-issue.c',
),
'objects' : ['systemd-ssh-generator'],
}, },
] ]

View File

@ -17,7 +17,6 @@
#include "socket-netlink.h" #include "socket-netlink.h"
#include "socket-util.h" #include "socket-util.h"
#include "special.h" #include "special.h"
#include "ssh-util.h"
#include "string-util.h" #include "string-util.h"
#include "strv.h" #include "strv.h"
#include "virt.h" #include "virt.h"
@ -213,15 +212,29 @@ static int add_vsock_socket(
return 0; return 0;
} }
r = vsock_open_or_warn(/* ret= */ NULL); _cleanup_close_ int vsock_fd = socket(AF_VSOCK, SOCK_STREAM|SOCK_CLOEXEC, 0);
if (r <= 0) if (vsock_fd < 0) {
return r; if (ERRNO_IS_NOT_SUPPORTED(errno)) {
log_debug("Not creating AF_VSOCK ssh listener, since AF_VSOCK is not available.");
return 0;
}
return log_error_errno(errno, "Unable to test if AF_VSOCK is available: %m");
}
vsock_fd = safe_close(vsock_fd);
/* Determine the local CID so that we can log it to help users to connect to this VM */ /* Determine the local CID so that we can log it to help users to connect to this VM */
unsigned local_cid; unsigned local_cid;
r = vsock_get_local_cid_or_warn(&local_cid); r = vsock_get_local_cid(&local_cid);
if (r <= 0) if (r < 0) {
return r; if (ERRNO_IS_DEVICE_ABSENT(r)) {
log_debug("Not creating AF_VSOCK ssh listener, since /dev/vsock is not available (even though AF_VSOCK is).");
return 0;
}
return log_error_errno(r, "Failed to query local AF_VSOCK CID: %m");
}
r = make_sshd_template_unit( r = make_sshd_template_unit(
dest, dest,

View File

@ -15,7 +15,7 @@
#include "mkdir.h" #include "mkdir.h"
#include "parse-argument.h" #include "parse-argument.h"
#include "pretty-print.h" #include "pretty-print.h"
#include "ssh-util.h" #include "socket-util.h"
#include "string-util.h" #include "string-util.h"
#include "tmpfile-util.h" #include "tmpfile-util.h"
#include "virt.h" #include "virt.h"
@ -135,11 +135,33 @@ static int acquire_cid(unsigned *ret_cid) {
return 0; return 0;
} }
r = vsock_open_or_warn(/* ret= */ NULL); _cleanup_close_ int vsock_fd = socket(AF_VSOCK, SOCK_STREAM|SOCK_CLOEXEC, 0);
if (r <= 0) if (vsock_fd < 0) {
return r; if (ERRNO_IS_NOT_SUPPORTED(errno)) {
log_debug("Not creating issue file, since AF_VSOCK is not available.");
*ret_cid = 0;
return 0;
}
return vsock_get_local_cid_or_warn(ret_cid); return log_error_errno(errno, "Unable to test if AF_VSOCK is available: %m");
}
vsock_fd = safe_close(vsock_fd);
unsigned local_cid;
r = vsock_get_local_cid(&local_cid);
if (r < 0) {
if (ERRNO_IS_DEVICE_ABSENT(r)) {
log_debug("Not creating issue file, since /dev/vsock is not available (even though AF_VSOCK is).");
*ret_cid = 0;
return 0;
}
return log_error_errno(r, "Failed to query local AF_VSOCK CID: %m");
}
*ret_cid = local_cid;
return 1;
} }
static int run(int argc, char* argv[]) { static int run(int argc, char* argv[]) {

View File

@ -1,40 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <sys/socket.h>
#include <unistd.h>
#include "errno-util.h"
#include "log.h"
#include "socket-util.h"
#include "ssh-util.h"
int vsock_open_or_warn(int *ret) {
int fd = RET_NERRNO(socket(AF_VSOCK, SOCK_STREAM|SOCK_CLOEXEC, 0));
if (ERRNO_IS_NEG_NOT_SUPPORTED(fd))
log_debug_errno(fd, "AF_VSOCK is not available, ignoring: %m");
else if (fd < 0)
return log_error_errno(fd, "Unable to test if AF_VSOCK is available: %m");
if (ret)
*ret = fd;
else
close(fd);
return fd >= 0;
}
int vsock_get_local_cid_or_warn(unsigned *ret) {
int r;
r = vsock_get_local_cid(ret);
if (ERRNO_IS_NEG_DEVICE_ABSENT(r) || r == -EADDRNOTAVAIL) {
if (ERRNO_IS_NEG_DEVICE_ABSENT(r))
log_debug_errno(r, "/dev/vsock is not available (even though AF_VSOCK is), ignoring: %m");
if (ret)
*ret = 0; /* bogus value */
return 0;
}
if (r < 0)
return log_error_errno(r, "Failed to query local AF_VSOCK CID: %m");
return 1;
}

View File

@ -1,4 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
int vsock_open_or_warn(int *ret);
int vsock_get_local_cid_or_warn(unsigned *ret);

View File

@ -1,300 +0,0 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: LGPL-2.1-or-later
"""
Find unused symbols in a shared library.
This script analyzes a shared library and a list of executables that link
against it to determine which publicly exported symbols from the library
are not used by any of the executables or by the library itself internally.
The script checks for symbol usage in three ways:
1. Internal library references: Uses objdump -R to find relocations within
the library that reference its own exported symbols
2. Executable dependencies: Uses nm to find undefined symbols in executables
that match the library's exported symbols
3. Cross-references: Identifies symbols used across all provided binaries
This comprehensive approach ensures that symbols used internally by the
library are not incorrectly marked as unused.
"""
import argparse
import subprocess
import sys
from pathlib import Path
def get_exported_symbols(library_path):
"""
Extract all exported (public) symbols from a shared library.
Public API symbols (those starting with 'sd_') are excluded from the analysis
since they cannot be removed or made private due to API compatibility requirements.
Returns a set of symbol names that are defined and exported by the library.
"""
try:
result = subprocess.run(
['nm', '--dynamic', '--defined-only', '--extern-only', library_path],
capture_output=True,
text=True,
check=True
)
except subprocess.CalledProcessError as e:
print(f"Error: Failed to run nm on {library_path}: {e}", file=sys.stderr)
sys.exit(1)
except FileNotFoundError:
print("Error: 'nm' command not found. Please install binutils.", file=sys.stderr)
sys.exit(1)
symbols = set()
for line in result.stdout.splitlines():
parts = line.split()
if len(parts) >= 3:
# Format: address type name
symbol_type = parts[1]
symbol_name = parts[2]
# Include text (T) and data (D, B, R) symbols
if symbol_type in ('T', 'D', 'B', 'R', 'W'):
# Strip version information (e.g., @@SD_SHARED or @SD_SHARED)
symbol_name = symbol_name.split('@')[0]
# Skip public API symbols (those starting with sd_)
if symbol_name.startswith('sd_'):
continue
symbols.add(symbol_name)
return symbols
def get_undefined_symbols(executable_path):
"""
Extract all undefined symbols from an executable.
These are symbols that the executable expects to be provided by
shared libraries it links against.
"""
try:
result = subprocess.run(
['nm', '--dynamic', '--undefined-only', executable_path],
capture_output=True,
text=True,
check=True
)
except subprocess.CalledProcessError as e:
print(f"Warning: Failed to run nm on {executable_path}: {e}", file=sys.stderr)
return set()
except FileNotFoundError:
print("Error: 'nm' command not found. Please install binutils.", file=sys.stderr)
sys.exit(1)
symbols = set()
for line in result.stdout.splitlines():
parts = line.split()
if len(parts) >= 2:
# Format: type name (no address for undefined symbols)
symbol_name = parts[1]
# Strip version information (e.g., @SD_SHARED)
symbol_name = symbol_name.split('@')[0]
symbols.add(symbol_name)
return symbols
def verify_executable_links_library(executable_path, library_name):
"""
Verify that an executable actually links against the given library.
Returns True if the executable links against a library with the given name.
"""
try:
result = subprocess.run(
['ldd', executable_path],
capture_output=True,
text=True,
check=True
)
except (subprocess.CalledProcessError, FileNotFoundError):
# If ldd fails or doesn't exist, we'll skip the verification
return True
# Check if library_name appears in the ldd output
for line in result.stdout.splitlines():
if library_name in line:
return True
return False
def get_library_internal_references(library_path, exported_symbols):
"""
Find which exported symbols are referenced internally within the library itself.
This uses objdump to look for relocations that reference the exported symbols.
"""
try:
result = subprocess.run(
['objdump', '-R', library_path],
capture_output=True,
text=True,
check=True
)
except subprocess.CalledProcessError as e:
print(f"Warning: Failed to run objdump on {library_path}: {e}", file=sys.stderr)
return set()
except FileNotFoundError:
print("Warning: 'objdump' command not found. Internal references won't be detected.",
file=sys.stderr)
return set()
internal_refs = set()
for line in result.stdout.splitlines():
parts = line.split()
if len(parts) >= 3:
# objdump -R format: offset type symbol
# The symbol is typically the last field
symbol_name = parts[-1]
# Strip version information
symbol_name = symbol_name.split('@')[0]
# Only include if it's one of our exported symbols
if symbol_name in exported_symbols:
internal_refs.add(symbol_name)
return internal_refs
def find_unused_symbols(library_path, executable_paths, verify_linkage=True):
"""
Find symbols exported by the library that are not used by any executable.
Args:
library_path: Path to the shared library
executable_paths: List of paths to executables
verify_linkage: Whether to verify executables link against the library
Returns:
Tuple of (unused_symbols, exported_symbols, used_symbols)
"""
library_name = Path(library_path).name
# Get all exported symbols from the library (excluding public API symbols)
exported_symbols = get_exported_symbols(library_path)
if not exported_symbols:
print(f"Warning: No exported symbols found in {library_path}", file=sys.stderr)
return set(), set(), set()
# Collect all symbols used by the executables
used_symbols = set()
# First, check if the library references its own exported symbols internally
internal_refs = get_library_internal_references(library_path, exported_symbols)
used_symbols.update(internal_refs)
for exe_path in executable_paths:
# Optionally verify linkage
if verify_linkage and not verify_executable_links_library(exe_path, library_name):
print(f"Warning: {exe_path} does not appear to link against {library_name}",
file=sys.stderr)
undefined_symbols = get_undefined_symbols(exe_path)
# Only count symbols that are actually exported by our library
used_symbols.update(undefined_symbols & exported_symbols)
# Find unused symbols
unused_symbols = exported_symbols - used_symbols
return unused_symbols, exported_symbols, used_symbols
def main():
parser = argparse.ArgumentParser(
description='Find unused exported symbols in a shared library'
)
parser.add_argument(
'library',
help='Path to the shared library to analyze'
)
parser.add_argument(
'executables',
nargs='+',
help='Paths to executables that link against the library'
)
parser.add_argument(
'--no-verify-linkage',
action='store_true',
help='Skip verification that executables actually link against the library'
)
parser.add_argument(
'--show-used',
action='store_true',
help='Also show used symbols'
)
parser.add_argument(
'--stats-only',
action='store_true',
help='Only show statistics, not individual symbols'
)
args = parser.parse_args()
# Verify library exists
library_path = Path(args.library)
if not library_path.exists():
print(f"Error: Library not found: {library_path}", file=sys.stderr)
sys.exit(1)
# Verify executables exist
executable_paths = []
for exe in args.executables:
exe_path = Path(exe)
if not exe_path.exists():
print(f"Warning: Executable not found: {exe_path}", file=sys.stderr)
else:
executable_paths.append(str(exe_path))
if not executable_paths:
print("Error: No valid executables provided", file=sys.stderr)
sys.exit(1)
# Analyze symbols
unused, exported, used = find_unused_symbols(
str(library_path),
executable_paths,
verify_linkage=not args.no_verify_linkage
)
# Print results
print(f"Analysis of {library_path.name}")
print("=" * 70)
print(f"Total exported symbols: {len(exported)}")
print(f" (excluding public API symbols starting with 'sd_')")
print(f"Used symbols: {len(used)}")
print(f"Unused symbols: {len(unused)}")
print(f"Usage rate: {len(used)/len(exported)*100:.1f}%" if exported else "N/A")
print()
if not args.stats_only:
if unused:
print("Unused symbols:")
print("-" * 70)
for symbol in sorted(unused):
print(f" {symbol}")
print()
else:
print("All exported symbols are used!")
print()
if args.show_used and used:
print("Used symbols:")
print("-" * 70)
for symbol in sorted(used):
print(f" {symbol}")
print()
# Exit with non-zero if there are unused symbols (useful for CI)
sys.exit(0 if not unused else 1)
if __name__ == '__main__':
main()