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

Compare commits

..

No commits in common. "40258ae0616b6886d62ef5d7c0d96515c03f7246" and "e4d294c46d9cb0f57fb2125cd6f2eec29f0ecc49" have entirely different histories.

30 changed files with 430 additions and 1079 deletions

View File

@ -364,10 +364,3 @@ disk images with `--image=` or similar:
against any of the certificates in `/etc/verity.d/*.crt` (and similar
directores in `/usr/lib/`, `/run`, …) or passed to the kernel for validation
against its built-in certificates.
`systemd-cryptsetup`:
* `$SYSTEMD_CRYPTSETUP_USE_TOKEN_MODULE` takes a boolean, which controls
whether to use the libcryptsetup "token" plugin module logic even when
activating via FIDO2, PKCS#11, TPM2, i.e. mechanisms natively supported by
`systemd-cryptsetup`. Defaults to enabled.

View File

@ -677,18 +677,6 @@
of the current PCR state.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>token-timeout=</option></term>
<listitem><para>Specifies how long to wait at most for configured security devices (i.e. FIDO2,
PKCS#11, TPM2) to show up. Takes a time value in seconds (but other time units may be specified too,
see <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry>
for supported formats). Defaults to 30s. Once the specified timeout elapsed authentication via
password is attempted. Note that this timeout applies to waiting for the security device to show up —
it does not apply to the PIN prompt for the device (should one be needed) or similar. Pass 0 to turn
off the time-out and wait forever.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>try-empty-password=</option></term>
@ -701,9 +689,13 @@
<varlistentry>
<term><option>x-systemd.device-timeout=</option></term>
<listitem><para>Specifies how long systemd should wait for a block device to show up before
giving up on the entry. The argument is a time in seconds or explicitly specified units of
<literal>s</literal>, <literal>min</literal>, <literal>h</literal>, <literal>ms</literal>.
<listitem><para>Specifies how long systemd should wait for a device to show up
before giving up on the entry. The argument is a time in seconds or explicitly
specified units of
<literal>s</literal>,
<literal>min</literal>,
<literal>h</literal>,
<literal>ms</literal>.
</para></listitem>
</varlistentry>

View File

@ -7,7 +7,6 @@
#include <sys/types.h>
#include "ether-addr-util.h"
#include "hexdecoct.h"
#include "macro.h"
#include "string-util.h"
@ -16,13 +15,12 @@ char* hw_addr_to_string(const struct hw_addr_data *addr, char buffer[HW_ADDR_TO_
assert(buffer);
assert(addr->length <= HW_ADDR_MAX_SIZE);
for (size_t i = 0, j = 0; i < addr->length; i++) {
buffer[j++] = hexchar(addr->bytes[i] >> 4);
buffer[j++] = hexchar(addr->bytes[i] & 0x0f);
buffer[j++] = ':';
for (size_t i = 0; i < addr->length; i++) {
sprintf(&buffer[3*i], "%02"PRIx8, addr->bytes[i]);
if (i < addr->length - 1)
buffer[3*i + 2] = ':';
}
buffer[addr->length > 0 ? addr->length * 3 - 1 : 0] = '\0';
return buffer;
}

View File

@ -547,25 +547,12 @@ int read_virtual_file_fd(int fd, size_t max_size, char **ret_contents, size_t *r
return !truncated;
}
int read_virtual_file_at(
int dir_fd,
const char *filename,
size_t max_size,
char **ret_contents,
size_t *ret_size) {
int read_virtual_file(const char *filename, size_t max_size, char **ret_contents, size_t *ret_size) {
_cleanup_close_ int fd = -1;
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
assert(filename);
if (!filename) {
if (dir_fd == AT_FDCWD)
return -EBADF;
return read_virtual_file_fd(dir_fd, max_size, ret_contents, ret_size);
}
fd = openat(dir_fd, filename, O_RDONLY | O_NOCTTY | O_CLOEXEC);
fd = open(filename, O_RDONLY | O_NOCTTY | O_CLOEXEC);
if (fd < 0)
return -errno;

View File

@ -69,10 +69,7 @@ static inline int read_full_file(const char *filename, char **ret_contents, size
}
int read_virtual_file_fd(int fd, size_t max_size, char **ret_contents, size_t *ret_size);
int read_virtual_file_at(int dir_fd, const char *filename, size_t max_size, char **ret_contents, size_t *ret_size);
static inline int read_virtual_file(const char *filename, size_t max_size, char **ret_contents, size_t *ret_size) {
return read_virtual_file_at(AT_FDCWD, filename, max_size, ret_contents, ret_size);
}
int read_virtual_file(const char *filename, size_t max_size, char **ret_contents, size_t *ret_size);
static inline int read_full_virtual_file(const char *filename, char **ret_contents, size_t *ret_size) {
return read_virtual_file(filename, SIZE_MAX, ret_contents, ret_size);
}

View File

@ -119,57 +119,62 @@ int on_ac_power(void) {
bool found_offline = false, found_online = false;
_cleanup_closedir_ DIR *d = NULL;
struct dirent *de;
int r;
d = opendir("/sys/class/power_supply");
if (!d)
return errno == ENOENT ? true : -errno;
FOREACH_DIRENT(de, d, return -errno) {
_cleanup_close_ int device_fd = -1;
_cleanup_free_ char *contents = NULL;
unsigned v;
_cleanup_close_ int fd = -1, device = -1;
char contents[6];
ssize_t n;
device_fd = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC);
if (device_fd < 0) {
device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (device < 0) {
if (IN_SET(errno, ENOENT, ENOTDIR))
continue;
return -errno;
}
r = read_virtual_file_at(device_fd, "type", SIZE_MAX, &contents, NULL);
if (r == -ENOENT)
continue;
if (r < 0)
return r;
fd = openat(device, "type", O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (fd < 0) {
if (errno == ENOENT)
continue;
delete_trailing_chars(contents, NEWLINE);
return -errno;
}
/* We assume every power source is AC, except for batteries. See
* https://github.com/torvalds/linux/blob/4eef766b7d4d88f0b984781bc1bcb574a6eafdc7/include/linux/power_supply.h#L176
* for defined power source types. Also see:
* https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-class-power */
if (streq(contents, "Battery"))
n = read(fd, contents, sizeof(contents));
if (n < 0)
return -errno;
if (n != 6 || memcmp(contents, "Mains\n", 6))
continue;
contents = mfree(contents);
safe_close(fd);
fd = openat(device, "online", O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (fd < 0) {
if (errno == ENOENT)
continue;
r = read_virtual_file_at(device_fd, "online", SIZE_MAX, &contents, NULL);
if (r == -ENOENT)
continue;
if (r < 0)
return r;
return -errno;
}
delete_trailing_chars(contents, NEWLINE);
n = read(fd, contents, sizeof(contents));
if (n < 0)
return -errno;
r = safe_atou(contents, &v);
if (r < 0)
return r;
if (v > 0) /* At least 1 and 2 are defined as different types of 'online' */
if (n != 2 || contents[1] != '\n')
return -EIO;
if (contents[0] == '1') {
found_online = true;
else
break;
} else if (contents[0] == '0')
found_offline = true;
else
return -EIO;
}
return found_online || !found_offline;

View File

@ -276,6 +276,19 @@ static int detect_vm_dmi(void) {
#endif
}
static int detect_vm_xen(void) {
/* Check for Dom0 will be executed later in detect_vm_xen_dom0
The presence of /proc/xen indicates some form of a Xen domain */
if (access("/proc/xen", F_OK) < 0) {
log_debug("Virtualization XEN not found, /proc/xen does not exist");
return VIRTUALIZATION_NONE;
}
log_debug("Virtualization XEN found (/proc/xen exists)");
return VIRTUALIZATION_XEN;
}
#define XENFEAT_dom0 11 /* xen/include/public/features.h */
#define PATH_FEATURES "/sys/hypervisor/properties/features"
/* Returns -errno, or 0 for domU, or 1 for dom0 */
@ -329,26 +342,6 @@ static int detect_vm_xen_dom0(void) {
}
}
static int detect_vm_xen(void) {
int r;
/* The presence of /proc/xen indicates some form of a Xen domain */
if (access("/proc/xen", F_OK) < 0) {
log_debug("Virtualization XEN not found, /proc/xen does not exist");
return VIRTUALIZATION_NONE;
}
log_debug("Virtualization XEN found (/proc/xen exists)");
/* Ignore the Xen hypervisor if we are in Dom0 */
r = detect_vm_xen_dom0();
if (r < 0)
return r;
if (r > 0)
return VIRTUALIZATION_NONE;
return VIRTUALIZATION_XEN;
}
static int detect_vm_hypervisor(void) {
_cleanup_free_ char *hvtype = NULL;
int r;
@ -442,8 +435,7 @@ int detect_vm(void) {
*
* First, try to detect Oracle Virtualbox and Amazon EC2 Nitro, even if they use KVM, as well as Xen even if
* it cloaks as Microsoft Hyper-V. Attempt to detect uml at this stage also since it runs as a user-process
* nested inside other VMs. Also check for Xen now, because Xen PV mode does not override CPUID when nested
* inside another hypervisor.
* nested inside other VMs.
*
* Second, try to detect from CPUID, this will report KVM for whatever software is used even if info in DMI is
* overwritten.
@ -465,15 +457,6 @@ int detect_vm(void) {
else if (r != VIRTUALIZATION_NONE)
goto finish;
/* Detect Xen */
r = detect_vm_xen();
if (r < 0)
return r;
if (r == VIRTUALIZATION_VM_OTHER)
other = true;
else if (r != VIRTUALIZATION_NONE)
goto finish;
/* Detect from CPUID */
r = detect_vm_cpuid();
if (r < 0)
@ -493,7 +476,20 @@ int detect_vm(void) {
goto finish;
}
/* Check high-level hypervisor sysfs file */
/* x86 xen will most likely be detected by cpuid. If not (most likely
* because we're not an x86 guest), then we should try the /proc/xen
* directory next. If that's not found, then we check for the high-level
* hypervisor sysfs file.
*/
r = detect_vm_xen();
if (r < 0)
return r;
if (r == VIRTUALIZATION_VM_OTHER)
other = true;
else if (r != VIRTUALIZATION_NONE)
goto finish;
r = detect_vm_hypervisor();
if (r < 0)
return r;
@ -515,7 +511,18 @@ int detect_vm(void) {
return r;
finish:
if (r == VIRTUALIZATION_NONE && other)
/* x86 xen Dom0 is detected as XEN in hypervisor and maybe others.
* In order to detect the Dom0 as not virtualization we need to
* double-check it */
if (r == VIRTUALIZATION_XEN) {
int dom0;
dom0 = detect_vm_xen_dom0();
if (dom0 < 0)
return dom0;
if (dom0 > 0)
r = VIRTUALIZATION_NONE;
} else if (r == VIRTUALIZATION_NONE && other)
r = VIRTUALIZATION_VM_OTHER;
cached_found = r;

View File

@ -1,147 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <efi.h>
#include <efilib.h>
#include "initrd.h"
#include "macro-fundamental.h"
#include "missing_efi.h"
/* extend LoadFileProtocol */
struct initrd_loader {
EFI_LOAD_FILE_PROTOCOL load_file;
const VOID *address;
UINTN length;
};
/* static structure for LINUX_INITRD_MEDIA device path
see https://github.com/torvalds/linux/blob/v5.13/drivers/firmware/efi/libstub/efi-stub-helper.c
*/
static const struct {
VENDOR_DEVICE_PATH vendor;
EFI_DEVICE_PATH end;
} _packed_ efi_initrd_device_path = {
.vendor = {
.Header = {
.Type = MEDIA_DEVICE_PATH,
.SubType = MEDIA_VENDOR_DP,
.Length = { sizeof(efi_initrd_device_path.vendor), 0 }
},
.Guid = LINUX_INITRD_MEDIA_GUID
},
.end = {
.Type = END_DEVICE_PATH_TYPE,
.SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE,
.Length = { sizeof(efi_initrd_device_path.end), 0 }
}
};
EFIAPI EFI_STATUS initrd_load_file(
EFI_LOAD_FILE_PROTOCOL *this,
EFI_DEVICE_PATH *file_path,
BOOLEAN boot_policy,
UINTN *buffer_size,
VOID *buffer) {
struct initrd_loader *loader;
if (!this || !buffer_size || !file_path)
return EFI_INVALID_PARAMETER;
if (boot_policy)
return EFI_UNSUPPORTED;
loader = (struct initrd_loader *) this;
if (loader->length == 0 || !loader->address)
return EFI_NOT_FOUND;
if (!buffer || *buffer_size < loader->length) {
*buffer_size = loader->length;
return EFI_BUFFER_TOO_SMALL;
}
CopyMem(buffer, loader->address, loader->length);
*buffer_size = loader->length;
return EFI_SUCCESS;
}
EFI_STATUS initrd_register(
const VOID *initrd_address,
UINTN initrd_length,
EFI_HANDLE *ret_initrd_handle) {
EFI_STATUS err;
EFI_DEVICE_PATH *dp = (EFI_DEVICE_PATH *) &efi_initrd_device_path;
EFI_HANDLE handle;
struct initrd_loader *loader;
assert(ret_initrd_handle);
if (!initrd_address || initrd_length == 0)
return EFI_SUCCESS;
/* check if a LINUX_INITRD_MEDIA_GUID DevicePath is already registed.
LocateDevicePath checks for the "closest DevicePath" and returns its handle,
where as InstallMultipleProtocolInterfaces only maches identical DevicePaths.
*/
err = uefi_call_wrapper(BS->LocateDevicePath, 3, &EfiLoadFile2Protocol, &dp, &handle);
if (err != EFI_NOT_FOUND) /* InitrdMedia is already registered */
return EFI_ALREADY_STARTED;
loader = AllocatePool(sizeof(struct initrd_loader));
if (!loader)
return EFI_OUT_OF_RESOURCES;
*loader = (struct initrd_loader) {
.load_file.LoadFile = initrd_load_file,
.address = initrd_address,
.length = initrd_length
};
/* create a new handle and register the LoadFile2 protocol with the InitrdMediaPath on it */
err = uefi_call_wrapper(
BS->InstallMultipleProtocolInterfaces, 8,
ret_initrd_handle,
&DevicePathProtocol, &efi_initrd_device_path,
&EfiLoadFile2Protocol, loader,
NULL);
if (EFI_ERROR(err))
FreePool(loader);
return err;
}
EFI_STATUS initrd_unregister(EFI_HANDLE initrd_handle) {
EFI_STATUS err;
struct initrd_loader *loader;
if (!initrd_handle)
return EFI_SUCCESS;
/* get the LoadFile2 protocol that we allocated earlier */
err = uefi_call_wrapper(
BS->OpenProtocol, 6,
initrd_handle, &EfiLoadFile2Protocol, (VOID **) &loader,
NULL, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
if (EFI_ERROR(err))
return err;
/* close the handle */
(void) uefi_call_wrapper(
BS->CloseProtocol, 4,
initrd_handle, &EfiLoadFile2Protocol, NULL, NULL);
/* uninstall all protocols thus destroying the handle */
err = uefi_call_wrapper(
BS->UninstallMultipleProtocolInterfaces, 6,
initrd_handle,
&DevicePathProtocol, &efi_initrd_device_path,
&EfiLoadFile2Protocol, loader,
NULL);
if (EFI_ERROR(err))
return err;
initrd_handle = NULL;
FreePool(loader);
return EFI_SUCCESS;
}

View File

@ -1,11 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <efi.h>
EFI_STATUS initrd_register(
const VOID *initrd_address,
UINTN initrd_length,
EFI_HANDLE *ret_initrd_handle);
EFI_STATUS initrd_unregister(EFI_HANDLE initrd_handle);

View File

@ -4,7 +4,6 @@
#include <efilib.h>
#include "linux.h"
#include "initrd.h"
#include "util.h"
#ifdef __i386__
@ -29,25 +28,21 @@ static VOID linux_efi_handover(EFI_HANDLE image, struct boot_params *params) {
handover(image, ST, params);
}
EFI_STATUS linux_exec(
EFI_HANDLE image,
const CHAR8 *cmdline, UINTN cmdline_len,
const VOID *linux_buffer,
const VOID *initrd_buffer, UINTN initrd_length) {
EFI_STATUS linux_exec(EFI_HANDLE image,
CHAR8 *cmdline, UINTN cmdline_len,
UINTN linux_addr,
UINTN initrd_addr, UINTN initrd_size) {
const struct boot_params *image_params;
struct boot_params *boot_params;
EFI_HANDLE initrd_handle = NULL;
EFI_PHYSICAL_ADDRESS addr;
UINT8 setup_sectors;
EFI_STATUS err;
assert(image);
assert(cmdline || cmdline_len == 0);
assert(linux_buffer);
assert(initrd_buffer || initrd_length == 0);
assert(cmdline);
image_params = (const struct boot_params *) linux_buffer;
image_params = (const struct boot_params *) linux_addr;
if (image_params->hdr.boot_flag != 0xAA55 ||
image_params->hdr.header != SETUP_MAGIC ||
@ -70,7 +65,7 @@ EFI_STATUS linux_exec(
boot_params->hdr = image_params->hdr;
boot_params->hdr.type_of_loader = 0xff;
setup_sectors = image_params->hdr.setup_sects > 0 ? image_params->hdr.setup_sects : 4;
boot_params->hdr.code32_start = (UINT32) POINTER_TO_PHYSICAL_ADDRESS(linux_buffer) + (setup_sectors + 1) * 512;
boot_params->hdr.code32_start = (UINT32)linux_addr + (setup_sectors + 1) * 512;
if (cmdline) {
addr = 0xA0000;
@ -89,21 +84,9 @@ EFI_STATUS linux_exec(
boot_params->hdr.cmd_line_ptr = (UINT32) addr;
}
/* Providing the initrd via LINUX_INITRD_MEDIA_GUID is only supported by Linux 5.8+ (5.7+ on ARM64).
Until supported kernels become more established, we continue to set ramdisk in the handover struct.
This value is overridden by kernels that support LINUX_INITRD_MEDIA_GUID.
If you need to know which protocol was used by the kernel, pass "efi=debug" to the kernel,
this will print a line when InitrdMediaGuid was successfully used to load the initrd.
*/
boot_params->hdr.ramdisk_image = (UINT32) POINTER_TO_PHYSICAL_ADDRESS(initrd_buffer);
boot_params->hdr.ramdisk_size = (UINT32) initrd_length;
boot_params->hdr.ramdisk_image = (UINT32) initrd_addr;
boot_params->hdr.ramdisk_size = (UINT32) initrd_size;
/* register LINUX_INITRD_MEDIA_GUID */
err = initrd_register(initrd_buffer, initrd_length, &initrd_handle);
if (EFI_ERROR(err))
return err;
linux_efi_handover(image, boot_params);
(void) initrd_unregister(initrd_handle);
initrd_handle = NULL;
return EFI_LOAD_ERROR;
}

View File

@ -84,8 +84,7 @@ struct boot_params {
UINT8 _pad9[276];
} _packed_;
EFI_STATUS linux_exec(
EFI_HANDLE image,
const CHAR8 *cmdline, UINTN cmdline_len,
const VOID *linux_buffer,
const VOID *initrd_buffer, UINTN initrd_length);
EFI_STATUS linux_exec(EFI_HANDLE image,
CHAR8 *cmdline, UINTN cmdline_size,
UINTN linux_addr,
UINTN initrd_addr, UINTN initrd_size);

View File

@ -38,7 +38,6 @@ systemd_boot_sources = '''
stub_sources = '''
linux.c
initrd.c
splash.c
stub.c
cpio.c

View File

@ -331,12 +331,3 @@ typedef struct tdEFI_TCG2_PROTOCOL {
} EFI_TCG2;
#endif
#ifndef EFI_LOAD_FILE2_PROTOCOL_GUID
#define EFI_LOAD_FILE2_PROTOCOL_GUID \
{0x4006c0c1, 0xfcb3, 0x403e, {0x99, 0x6d, 0x4a, 0x6c, 0x87, 0x24, 0xe0, 0x6d} }
#define EfiLoadFile2Protocol ((EFI_GUID)EFI_LOAD_FILE2_PROTOCOL_GUID)
#endif
#define LINUX_INITRD_MEDIA_GUID \
{0x5568e427, 0x68fc, 0x4f3d, {0xac, 0x74, 0xca, 0x55, 0x52, 0x31, 0xcc, 0x68} }

View File

@ -249,9 +249,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
}
}
err = linux_exec(image, cmdline, cmdline_len,
PHYSICAL_ADDRESS_TO_POINTER(linux_base),
PHYSICAL_ADDRESS_TO_POINTER(initrd_base), initrd_size);
err = linux_exec(image, cmdline, cmdline_len, linux_base, initrd_base, initrd_size);
graphics_mode(FALSE);
return log_error_status_stall(err, L"Execution of embedded linux image failed: %r", err);
}

View File

@ -32,7 +32,6 @@ int acquire_fido2_key(
_cleanup_strv_free_erase_ char **pins = NULL;
_cleanup_free_ void *loaded_salt = NULL;
bool device_exists = false;
const char *salt;
size_t salt_size;
char *e;
@ -90,29 +89,13 @@ int acquire_fido2_key(
-ENOANO, /* needs pin */
-ENOLCK)) /* pin incorrect */
return r;
device_exists = true; /* that a PIN is needed/wasn't correct means that we managed to
* talk to a device */
}
pins = strv_free_erase(pins);
if (headless)
return log_error_errno(SYNTHETIC_ERRNO(ENOPKG), "PIN querying disabled via 'headless' option. Use the '$PIN' environment variable.");
if (!device_exists) {
/* Before we inquire for the PIN we'll need, if we never talked to the device, check
* if the device actually is plugged in. Otherwise we'll ask for the PIN already when
* the device is not plugged in, which is confusing. */
r = fido2_have_device(device);
if (r < 0)
return r;
if (r == 0) /* no device found, return EAGAIN so that caller will wait/watch udev */
return -EAGAIN;
device_exists = true; /* now we know for sure, a device exists, no need to ask again */
}
pins = strv_free_erase(pins);
r = ask_password_auto("Please enter security token PIN:", "drive-harddisk", NULL, "fido2-pin", "cryptsetup.fido2-pin", until, ask_password_flags, &pins);
if (r < 0)
return log_error_errno(r, "Failed to ask for user password: %m");

View File

@ -18,7 +18,6 @@
#include "cryptsetup-util.h"
#include "device-util.h"
#include "efi-loader.h"
#include "env-util.h"
#include "escape.h"
#include "fileio.h"
#include "fs-util.h"
@ -83,7 +82,6 @@ static char *arg_tpm2_device = NULL;
static bool arg_tpm2_device_auto = false;
static uint32_t arg_tpm2_pcr_mask = UINT32_MAX;
static bool arg_headless = false;
static usec_t arg_token_timeout_usec = 30*USEC_PER_SEC;
STATIC_DESTRUCTOR_REGISTER(arg_cipher, freep);
STATIC_DESTRUCTOR_REGISTER(arg_hash, freep);
@ -411,15 +409,7 @@ static int parse_one_option(const char *option) {
} else if (streq(option, "headless"))
arg_headless = true;
else if ((val = startswith(option, "token-timeout="))) {
r = parse_sec_fix_0(val, &arg_token_timeout_usec);
if (r < 0) {
log_error_errno(r, "Failed to parse %s, ignoring: %m", option);
return 0;
}
} else if (!streq(option, "x-initrd.attach"))
else if (!streq(option, "x-initrd.attach"))
log_warning("Encountered unknown /etc/crypttab option '%s', ignoring.", option);
return 0;
@ -720,25 +710,11 @@ static char *make_bindname(const char *volume) {
return s;
}
static int make_security_device_monitor(
sd_event **ret_event,
sd_device_monitor **ret_monitor) {
static int make_security_device_monitor(sd_event *event, sd_device_monitor **ret) {
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor = NULL;
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
int r;
assert(ret_event);
assert(ret_monitor);
/* Waits for a device with "security-device" tag to show up in udev */
r = sd_event_default(&event);
if (r < 0)
return log_error_errno(r, "Failed to allocate event loop: %m");
r = sd_event_add_time_relative(event, NULL, CLOCK_MONOTONIC, arg_token_timeout_usec, USEC_PER_SEC, NULL, INT_TO_PTR(-ETIMEDOUT));
if (r < 0)
return log_error_errno(r, "Failed to install timeout event source: %m");
assert(ret);
r = sd_device_monitor_new(&monitor);
if (r < 0)
@ -756,61 +732,13 @@ static int make_security_device_monitor(
if (r < 0)
return log_error_errno(r, "Failed to start device monitor: %m");
*ret_event = TAKE_PTR(event);
*ret_monitor = TAKE_PTR(monitor);
*ret = TAKE_PTR(monitor);
return 0;
}
static int run_security_device_monitor(
sd_event *event,
sd_device_monitor *monitor) {
bool processed = false;
int r;
assert(event);
assert(monitor);
/* Runs the event loop for the device monitor until either something happens, or the time-out is
* hit. */
for (;;) {
int x;
r = sd_event_get_exit_code(event, &x);
if (r < 0) {
if (r != -ENODATA)
return log_error_errno(r, "Failed to query exit code from event loop: %m");
/* On ENODATA we aren't told to exit yet. */
} else {
assert(x == -ETIMEDOUT);
return log_notice_errno(SYNTHETIC_ERRNO(EAGAIN),
"Timed out waiting for security device, aborting security device based authentication attempt.");
}
/* Wait for one event, and then eat all subsequent events until there are no further ones */
r = sd_event_run(event, processed ? 0 : UINT64_MAX);
if (r < 0)
return log_error_errno(r, "Failed to run event loop: %m");
if (r == 0) /* no events queued anymore */
return 0;
processed = true;
}
}
static bool libcryptsetup_plugins_support(void) {
#if HAVE_LIBCRYPTSETUP_PLUGINS
int r;
/* Permit a way to disable libcryptsetup token module support, for debugging purposes. */
r = getenv_bool("SYSTEMD_CRYPTSETUP_USE_TOKEN_MODULE");
if (r < 0 && r != -ENXIO)
log_debug_errno(r, "Failed to parse $SYSTEMD_CRYPTSETUP_USE_TOKEN_MODULE env var: %m");
if (r == 0)
return false;
return crypt_token_external_path();
return crypt_token_external_path() != NULL;
#else
return false;
#endif
@ -848,11 +776,11 @@ static int attach_luks2_by_fido2(
void *usrptr,
uint32_t activation_flags) {
int r = -EOPNOTSUPP;
#if HAVE_LIBCRYPTSETUP_PLUGINS
AskPasswordFlags flags = ASK_PASSWORD_PUSH_CACHE | ASK_PASSWORD_ACCEPT_CACHED;
_cleanup_strv_free_erase_ char **pins = NULL;
char **p;
int r;
_cleanup_strv_free_erase_ char **pins = NULL;
AskPasswordFlags flags = ASK_PASSWORD_PUSH_CACHE | ASK_PASSWORD_ACCEPT_CACHED;
r = crypt_activate_by_token_pin(cd, name, "systemd-fido2", CRYPT_ANY_TOKEN, NULL, 0, usrptr, activation_flags);
if (r > 0) /* returns unlocked keyslot id on success */
@ -875,6 +803,20 @@ static int attach_luks2_by_fido2(
if (headless)
return log_error_errno(SYNTHETIC_ERRNO(ENOPKG), "PIN querying disabled via 'headless' option. Use the '$PIN' environment variable.");
pins = strv_free_erase(pins);
r = ask_password_auto("Please enter security token PIN:", "drive-harddisk", NULL, "fido2-pin", "cryptsetup.fido2-pin", until, flags, &pins);
if (r < 0)
return r;
STRV_FOREACH(p, pins) {
r = crypt_activate_by_token_pin(cd, name, "systemd-fido2", CRYPT_ANY_TOKEN, *p, strlen(*p), usrptr, activation_flags);
if (r > 0) /* returns unlocked keyslot id on success */
r = 0;
if (r != -ENOANO) /* needs pin or pin is wrong */
return r;
}
flags &= ~ASK_PASSWORD_ACCEPT_CACHED;
for (;;) {
pins = strv_free_erase(pins);
r = ask_password_auto("Please enter security token PIN:", "drive-harddisk", NULL, "fido2-pin", "cryptsetup.fido2-pin", until, flags, &pins);
@ -888,13 +830,9 @@ static int attach_luks2_by_fido2(
if (r != -ENOANO) /* needs pin or pin is wrong */
return r;
}
flags &= ~ASK_PASSWORD_ACCEPT_CACHED;
}
return r;
#else
return -EOPNOTSUPP;
#endif
return r;
}
static int attach_luks_or_plain_or_bitlk_by_fido2(
@ -970,6 +908,8 @@ static int attach_luks_or_plain_or_bitlk_by_fido2(
return log_oom();
for (;;) {
bool processed = false;
if (use_libcryptsetup_plugin && !arg_fido2_cid) {
r = attach_luks2_by_fido2(cd, name, until, arg_headless, arg_fido2_device, flags);
if (IN_SET(r, -ENOTUNIQ, -ENXIO, -ENOENT))
@ -1003,7 +943,11 @@ static int attach_luks_or_plain_or_bitlk_by_fido2(
assert(!event);
r = make_security_device_monitor(&event, &monitor);
r = sd_event_default(&event);
if (r < 0)
return log_error_errno(r, "Failed to allocate event loop: %m");
r = make_security_device_monitor(event, &monitor);
if (r < 0)
return r;
@ -1014,9 +958,17 @@ static int attach_luks_or_plain_or_bitlk_by_fido2(
continue;
}
r = run_security_device_monitor(event, monitor);
if (r < 0)
return r;
for (;;) {
/* Wait for one event, and then eat all subsequent events until there are no
* further ones */
r = sd_event_run(event, processed ? 0 : UINT64_MAX);
if (r < 0)
return log_error_errno(r, "Failed to run event loop: %m");
if (r == 0)
break;
processed = true;
}
log_debug("Got one or more potentially relevant udev events, rescanning FIDO2...");
}
@ -1052,10 +1004,9 @@ static int attach_luks2_by_pkcs11(
bool headless,
uint32_t flags) {
int r = -EOPNOTSUPP;
#if HAVE_LIBCRYPTSETUP_PLUGINS
int r;
if (!streq_ptr(crypt_get_type(cd), CRYPT_LUKS2))
if (!crypt_get_type(cd) || strcmp(crypt_get_type(cd), CRYPT_LUKS2))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Automatic PKCS#11 metadata requires LUKS2 device.");
systemd_pkcs11_plugin_params params = {
@ -1067,11 +1018,8 @@ static int attach_luks2_by_pkcs11(
r = crypt_activate_by_token_pin(cd, name, "systemd-pkcs11", CRYPT_ANY_TOKEN, NULL, 0, &params, flags);
if (r > 0) /* returns unlocked keyslot id on success */
r = 0;
return r;
#else
return -EOPNOTSUPP;
#endif
return r;
}
static int attach_luks_or_plain_or_bitlk_by_pkcs11(
@ -1123,6 +1071,8 @@ static int attach_luks_or_plain_or_bitlk_by_pkcs11(
return log_oom();
for (;;) {
bool processed = false;
if (use_libcryptsetup_plugin && arg_pkcs11_uri_auto)
r = attach_luks2_by_pkcs11(cd, name, friendly, until, arg_headless, flags);
else {
@ -1148,7 +1098,11 @@ static int attach_luks_or_plain_or_bitlk_by_pkcs11(
assert(!event);
r = make_security_device_monitor(&event, &monitor);
r = sd_event_default(&event);
if (r < 0)
return log_error_errno(r, "Failed to allocate event loop: %m");
r = make_security_device_monitor(event, &monitor);
if (r < 0)
return r;
@ -1160,9 +1114,17 @@ static int attach_luks_or_plain_or_bitlk_by_pkcs11(
continue;
}
r = run_security_device_monitor(event, monitor);
if (r < 0)
return r;
for (;;) {
/* Wait for one event, and then eat all subsequent events until there are no
* further ones */
r = sd_event_run(event, processed ? 0 : UINT64_MAX);
if (r < 0)
return log_error_errno(r, "Failed to run event loop: %m");
if (r == 0)
break;
processed = true;
}
log_debug("Got one or more potentially relevant udev events, rescanning PKCS#11...");
}
@ -1197,24 +1159,11 @@ static int attach_luks_or_plain_or_bitlk_by_pkcs11(
return 0;
}
static int make_tpm2_device_monitor(
sd_event **ret_event,
sd_device_monitor **ret_monitor) {
static int make_tpm2_device_monitor(sd_event *event, sd_device_monitor **ret) {
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor = NULL;
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
int r;
assert(ret_event);
assert(ret_monitor);
r = sd_event_default(&event);
if (r < 0)
return log_error_errno(r, "Failed to allocate event loop: %m");
r = sd_event_add_time_relative(event, NULL, CLOCK_MONOTONIC, arg_token_timeout_usec, USEC_PER_SEC, NULL, INT_TO_PTR(-ETIMEDOUT));
if (r < 0)
return log_error_errno(r, "Failed to install timeout event source: %m");
assert(ret);
r = sd_device_monitor_new(&monitor);
if (r < 0)
@ -1232,8 +1181,7 @@ static int make_tpm2_device_monitor(
if (r < 0)
return log_error_errno(r, "Failed to start device monitor: %m");
*ret_event = TAKE_PTR(event);
*ret_monitor = TAKE_PTR(monitor);
*ret = TAKE_PTR(monitor);
return 0;
}
@ -1290,6 +1238,8 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
return log_oom();
for (;;) {
bool processed = false;
if (key_file || key_data) {
/* If key data is specified, use that */
@ -1393,7 +1343,11 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
return log_notice_errno(SYNTHETIC_ERRNO(EAGAIN),
"No TPM2 hardware discovered and EFI bios indicates no support for it either, assuming TPM2-less system, falling back to traditional unocking.");
r = make_tpm2_device_monitor(&event, &monitor);
r = sd_event_default(&event);
if (r < 0)
return log_error_errno(r, "Failed to allocate event loop: %m");
r = make_tpm2_device_monitor(event, &monitor);
if (r < 0)
return r;
@ -1404,9 +1358,17 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
continue;
}
r = run_security_device_monitor(event, monitor);
if (r < 0)
return r;
for (;;) {
/* Wait for one event, and then eat all subsequent events until there are no
* further ones */
r = sd_event_run(event, processed ? 0 : UINT64_MAX);
if (r < 0)
return log_error_errno(r, "Failed to run event loop: %m");
if (r == 0)
break;
processed = true;
}
log_debug("Got one or more potentially relevant udev events, rescanning for TPM2...");
}

View File

@ -18,15 +18,13 @@ static inline int device_new_from_watch_handle(sd_device **ret, int wd) {
}
int device_get_device_id(sd_device *device, const char **ret);
int device_get_devlink_priority(sd_device *device, int *priority);
int device_get_watch_handle(sd_device *device);
int device_get_devnode_mode(sd_device *device, mode_t *mode);
int device_get_devnode_uid(sd_device *device, uid_t *uid);
int device_get_devnode_gid(sd_device *device, gid_t *gid);
int device_cache_sysattr_value(sd_device *device, const char *key, char *value);
int device_get_cached_sysattr_value(sd_device *device, const char *key, const char **ret_value);
void device_seal(sd_device *device);
void device_set_is_initialized(sd_device *device);
int device_set_watch_handle(sd_device *device, int wd);

View File

@ -1941,7 +1941,7 @@ _public_ int sd_device_get_trigger_uuid(sd_device *device, sd_id128_t *ret) {
return 0;
}
int device_cache_sysattr_value(sd_device *device, const char *key, char *value) {
static int device_cache_sysattr_value(sd_device *device, const char *key, char *value) {
_unused_ _cleanup_free_ char *old_value = NULL;
_cleanup_free_ char *new_key = NULL;
int r;
@ -1969,19 +1969,18 @@ int device_cache_sysattr_value(sd_device *device, const char *key, char *value)
return 0;
}
int device_get_cached_sysattr_value(sd_device *device, const char *key, const char **ret_value) {
const char *k = NULL, *value;
static int device_get_cached_sysattr_value(sd_device *device, const char *_key, const char **_value) {
const char *key = NULL, *value;
assert(device);
assert(key);
assert(_key);
value = hashmap_get2(device->sysattr_values, key, (void **) &k);
if (!k)
return -ESTALE; /* We have not read the attribute. */
if (!value)
return -ENOENT; /* We have looked up the attribute before and it did not exist. */
if (ret_value)
*ret_value = value;
value = hashmap_get2(device->sysattr_values, _key, (void **) &key);
if (!key)
return -ENOENT;
if (_value)
*_value = value;
return 0;
}
@ -1989,7 +1988,7 @@ int device_get_cached_sysattr_value(sd_device *device, const char *key, const ch
* with a NULL value in the cache, otherwise the returned string is stored */
_public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **ret_value) {
_cleanup_free_ char *value = NULL;
const char *path, *syspath;
const char *path, *syspath, *cached_value = NULL;
struct stat statbuf;
int r;
@ -1997,9 +1996,20 @@ _public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr,
assert_return(sysattr, -EINVAL);
/* look for possibly already cached result */
r = device_get_cached_sysattr_value(device, sysattr, ret_value);
if (r != -ESTALE)
return r;
r = device_get_cached_sysattr_value(device, sysattr, &cached_value);
if (r != -ENOENT) {
if (r < 0)
return r;
if (!cached_value)
/* we looked up the sysattr before and it did not exist */
return -ENOENT;
if (ret_value)
*ret_value = cached_value;
return 0;
}
r = sd_device_get_syspath(device, &syspath);
if (r < 0)

View File

@ -12,7 +12,6 @@
#include "memory-util.h"
#include "random-util.h"
#include "strv.h"
#include "unistd.h"
static void *libfido2_dl = NULL;
@ -1078,52 +1077,3 @@ finish:
"FIDO2 tokens not supported on this build.");
#endif
}
int fido2_have_device(const char *device) {
#if HAVE_LIBFIDO2
size_t allocated = 64, found = 0;
fido_dev_info_t *di = NULL;
int r;
/* Return == 0 if not devices are found, > 0 if at least one is found */
r = dlopen_libfido2();
if (r < 0)
return log_error_errno(r, "FIDO2 support is not installed.");
if (device) {
if (access(device, F_OK) < 0) {
if (errno == ENOENT)
return 0;
return log_error_errno(errno, "Failed to determine whether device '%s' exists: %m", device);
}
return 1;
}
di = sym_fido_dev_info_new(allocated);
if (!di)
return log_oom();
r = sym_fido_dev_info_manifest(di, allocated, &found);
if (r == FIDO_ERR_INTERNAL) {
/* The library returns FIDO_ERR_INTERNAL when no devices are found. I wish it wouldn't. */
r = 0;
goto finish;
}
if (r != FIDO_OK) {
r = log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to enumerate FIDO2 devices: %s", sym_fido_strerr(r));
goto finish;
}
r = found;
finish:
sym_fido_dev_info_free(&di, allocated);
return r;
#else
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"FIDO2 tokens not supported on this build.");
#endif
}

View File

@ -119,5 +119,3 @@ int fido2_generate_hmac_hash(
int fido2_list_devices(void);
int fido2_find_device_auto(char **ret);
int fido2_have_device(const char *device);

View File

@ -33,12 +33,12 @@ libudevd_core_sources = '''
udev-builtin-hwdb.c
udev-builtin-input_id.c
udev-builtin-keyboard.c
udev-builtin-net_id-netlink.c
udev-builtin-net_id-netlink.h
udev-builtin-net_id.c
udev-builtin-net_setup_link.c
udev-builtin-path_id.c
udev-builtin-usb_id.c
udev-netlink.c
udev-netlink.h
net/link-config.c
net/link-config.h
'''.split()
@ -212,9 +212,9 @@ tests += [
[threads,
libacl]],
[['src/udev/test-udev-netlink.c',
'src/udev/udev-netlink.c',
'src/udev/udev-netlink.h']],
[['src/udev/test-udev-builtin-net_id-netlink.c',
'src/udev/udev-builtin-net_id-netlink.c',
'src/udev/udev-builtin-net_id-netlink.h']],
[['src/udev/fido_id/test-fido-id-desc.c',
'src/udev/fido_id/fido_id_desc.c']],

View File

@ -0,0 +1,85 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "sd-device.h"
#include "arphrd-list.h"
#include "ether-addr-util.h"
#include "parse-util.h"
#include "tests.h"
#include "udev-builtin-net_id-netlink.h"
static void test_link_info_one(sd_netlink *rtnl, int ifindex) {
_cleanup_(link_info_clear) LinkInfo info = LINK_INFO_NULL;
_cleanup_(sd_device_unrefp) sd_device *dev = NULL;
unsigned iftype, iflink;
const char *s;
log_debug("/* %s(ifindex=%i) */", __func__, ifindex);
assert_se(link_info_get(&rtnl, ifindex, &info) >= 0);
assert_se(sd_device_new_from_ifindex(&dev, ifindex) >= 0);
/* check iftype */
log_debug("iftype: %"PRIu16" (%s)", info.iftype, strna(arphrd_to_name(info.iftype)));
assert_se(sd_device_get_sysattr_value(dev, "type", &s) >= 0);
assert_se(safe_atou(s, &iftype) >= 0);
assert_se(iftype == info.iftype);
/* check hardware address */
log_debug("hardware address: %s", HW_ADDR_TO_STR(&info.hw_addr));
assert_se(sd_device_get_sysattr_value(dev, "address", &s) >= 0);
assert_se(streq(s, HW_ADDR_TO_STR(&info.hw_addr)));
/* check ifname */
log_debug("ifname: %s", info.ifname);
assert_se(sd_device_get_sysname(dev, &s) >= 0);
assert_se(streq(s, info.ifname));
/* check iflink */
log_debug("iflink: %"PRIu32, info.iflink);
assert_se(sd_device_get_sysattr_value(dev, "iflink", &s) >= 0);
assert_se(safe_atou(s, &iflink) >= 0);
assert_se(iflink == info.iflink);
/* check phys_port_name */
log_debug("phys_port_name: %s (%s)",
strna(info.phys_port_name),
info.support_phys_port_name ? "supported" : "unsupported");
if (info.support_phys_port_name) {
s = NULL;
(void) sd_device_get_sysattr_value(dev, "phys_port_name", &s);
assert_se(streq_ptr(s, info.phys_port_name));
}
}
static void test_link_info_get(void) {
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
log_debug("/* %s */", __func__);
assert_se(sd_netlink_open(&rtnl) >= 0);
assert_se(sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0) >= 0);
assert_se(sd_netlink_message_request_dump(req, true) >= 0);
assert_se(sd_netlink_call(rtnl, req, 0, &reply) >= 0);
for (sd_netlink_message *reply_one = reply; reply_one; reply_one = sd_netlink_message_next(reply_one)) {
uint16_t nlmsg_type;
int ifindex;
assert_se(sd_netlink_message_get_type(reply_one, &nlmsg_type) >= 0);
assert_se(nlmsg_type == RTM_NEWLINK);
assert_se(sd_rtnl_message_link_get_ifindex(reply_one, &ifindex) >= 0);
test_link_info_one(rtnl, ifindex);
}
}
int main(int argc, char *argv[]) {
test_setup_logging(LOG_DEBUG);
test_link_info_get();
return 0;
}

View File

@ -1,165 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "sd-device.h"
#include "arphrd-list.h"
#include "ether-addr-util.h"
#include "parse-util.h"
#include "tests.h"
#include "udev-netlink.h"
static void test_link_info_one(sd_netlink *rtnl, int ifindex) {
_cleanup_(link_info_clear) LinkInfo info = LINK_INFO_NULL;
_cleanup_(sd_device_unrefp) sd_device *dev = NULL, *dev_with_netlink = NULL;
const char *s, *t;
unsigned u;
log_debug("/* %s(ifindex=%i) */", __func__, ifindex);
assert_se(link_info_get(&rtnl, ifindex, &info) >= 0);
assert_se(sd_device_new_from_ifindex(&dev, ifindex) >= 0);
assert_se(sd_device_new_from_ifindex(&dev_with_netlink, ifindex) >= 0);
/* check iftype */
log_debug("iftype: %"PRIu16" (%s)", info.iftype, strna(arphrd_to_name(info.iftype)));
assert_se(sd_device_get_sysattr_value(dev, "type", &s) >= 0);
assert_se(safe_atou(s, &u) >= 0);
assert_se(u == info.iftype);
assert_se(device_get_sysattr_value_maybe_from_netlink(dev_with_netlink, &rtnl, "type", &s) >= 0);
assert_se(safe_atou(s, &u) >= 0);
assert_se(u == info.iftype);
/* check hardware address length */
log_debug("hardware address length: %zu", info.hw_addr.length);
assert_se(sd_device_get_sysattr_value(dev, "addr_len", &s) >= 0);
assert_se(safe_atou(s, &u) >= 0);
assert_se(u == info.hw_addr.length);
assert_se(device_get_sysattr_value_maybe_from_netlink(dev_with_netlink, &rtnl, "addr_len", &s) >= 0);
assert_se(safe_atou(s, &u) >= 0);
assert_se(u == info.hw_addr.length);
/* check hardware address */
log_debug("hardware address: %s", HW_ADDR_TO_STR(&info.hw_addr));
assert_se(sd_device_get_sysattr_value(dev, "address", &s) >= 0);
assert_se(streq(s, HW_ADDR_TO_STR(&info.hw_addr)));
assert_se(device_get_sysattr_value_maybe_from_netlink(dev_with_netlink, &rtnl, "address", &s) >= 0);
assert_se(streq(s, HW_ADDR_TO_STR(&info.hw_addr)));
/* check broadcast address */
log_debug("broadcast address: %s", HW_ADDR_TO_STR(&info.broadcast));
assert_se(sd_device_get_sysattr_value(dev, "broadcast", &s) >= 0);
assert_se(streq(s, HW_ADDR_TO_STR(&info.broadcast)));
assert_se(device_get_sysattr_value_maybe_from_netlink(dev_with_netlink, &rtnl, "broadcast", &s) >= 0);
assert_se(streq(s, HW_ADDR_TO_STR(&info.broadcast)));
/* check ifname */
log_debug("ifname: %s", info.ifname);
assert_se(sd_device_get_sysname(dev, &s) >= 0);
assert_se(streq(s, info.ifname));
assert_se(sd_device_get_sysname(dev_with_netlink, &s) >= 0);
assert_se(streq(s, info.ifname));
/* check mtu */
log_debug("mtu: %"PRIu32, info.mtu);
assert_se(sd_device_get_sysattr_value(dev, "mtu", &s) >= 0);
assert_se(safe_atou(s, &u) >= 0);
assert_se(u == info.mtu);
assert_se(device_get_sysattr_value_maybe_from_netlink(dev_with_netlink, &rtnl, "mtu", &s) >= 0);
assert_se(safe_atou(s, &u) >= 0);
assert_se(u == info.mtu);
/* check iflink */
log_debug("iflink: %"PRIu32, info.iflink);
assert_se(sd_device_get_sysattr_value(dev, "iflink", &s) >= 0);
assert_se(safe_atou(s, &u) >= 0);
assert_se(u == info.iflink);
assert_se(device_get_sysattr_value_maybe_from_netlink(dev_with_netlink, &rtnl, "iflink", &s) >= 0);
assert_se(safe_atou(s, &u) >= 0);
assert_se(u == info.iflink);
/* check link_mode */
log_debug("link_mode: %"PRIu8, info.link_mode);
assert_se(sd_device_get_sysattr_value(dev, "link_mode", &s) >= 0);
assert_se(safe_atou(s, &u) >= 0);
assert_se(u == info.link_mode);
assert_se(device_get_sysattr_value_maybe_from_netlink(dev_with_netlink, &rtnl, "link_mode", &s) >= 0);
assert_se(safe_atou(s, &u) >= 0);
assert_se(u == info.link_mode);
/* check ifalias */
log_debug("ifalias: %s", strna(info.ifalias));
assert_se(sd_device_get_sysattr_value(dev, "ifalias", &s) >= 0);
assert_se(streq(s, strempty(info.ifalias)));
assert_se(device_get_sysattr_value_maybe_from_netlink(dev_with_netlink, &rtnl, "ifalias", &s) >= 0);
assert_se(streq(s, strempty(info.ifalias)));
/* check netdev_group */
log_debug("netdev_group: %"PRIu32, info.group);
assert_se(sd_device_get_sysattr_value(dev, "netdev_group", &s) >= 0);
assert_se(safe_atou(s, &u) >= 0);
assert_se(u == info.group);
assert_se(device_get_sysattr_value_maybe_from_netlink(dev_with_netlink, &rtnl, "netdev_group", &s) >= 0);
assert_se(safe_atou(s, &u) >= 0);
assert_se(u == info.group);
/* check phys_port_id */
log_debug("phys_port_id: (%s)",
info.phys_port_id_supported ? "supported" : "unsupported");
s = t = NULL;
(void) sd_device_get_sysattr_value(dev, "phys_port_id", &s);
(void) device_get_sysattr_value_maybe_from_netlink(dev_with_netlink, &rtnl, "phys_port_id", &t);
assert_se(streq_ptr(s, t));
/* check phys_switch_id */
log_debug("phys_switch_id: (%s)",
info.phys_switch_id_supported ? "supported" : "unsupported");
s = t = NULL;
(void) sd_device_get_sysattr_value(dev, "phys_switch_id", &s);
(void) device_get_sysattr_value_maybe_from_netlink(dev_with_netlink, &rtnl, "phys_switch_id", &t);
assert_se(streq_ptr(s, t));
/* check phys_port_name */
log_debug("phys_port_name: %s (%s)",
strna(info.phys_port_name),
info.phys_port_name_supported ? "supported" : "unsupported");
s = t = NULL;
(void) sd_device_get_sysattr_value(dev, "phys_port_name", &s);
(void) device_get_sysattr_value_maybe_from_netlink(dev_with_netlink, &rtnl, "phys_port_name", &t);
assert_se(streq_ptr(s, t));
if (info.phys_port_name_supported) {
assert_se(streq_ptr(s, info.phys_port_name));
assert_se(streq_ptr(t, info.phys_port_name));
}
}
static void test_link_info_get(void) {
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
log_debug("/* %s */", __func__);
assert_se(sd_netlink_open(&rtnl) >= 0);
assert_se(sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0) >= 0);
assert_se(sd_netlink_message_request_dump(req, true) >= 0);
assert_se(sd_netlink_call(rtnl, req, 0, &reply) >= 0);
for (sd_netlink_message *reply_one = reply; reply_one; reply_one = sd_netlink_message_next(reply_one)) {
uint16_t nlmsg_type;
int ifindex;
assert_se(sd_netlink_message_get_type(reply_one, &nlmsg_type) >= 0);
assert_se(nlmsg_type == RTM_NEWLINK);
assert_se(sd_rtnl_message_link_get_ifindex(reply_one, &ifindex) >= 0);
test_link_info_one(rtnl, ifindex);
}
}
int main(int argc, char *argv[]) {
test_setup_logging(LOG_DEBUG);
test_link_info_get();
return 0;
}

View File

@ -0,0 +1,87 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "netlink-util.h"
#include "udev-builtin-net_id-netlink.h"
void link_info_clear(LinkInfo *info) {
if (!info)
return;
info->ifname = mfree(info->ifname);
info->phys_port_name = mfree(info->phys_port_name);
}
int link_info_get(sd_netlink **rtnl, int ifindex, LinkInfo *ret) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL, *reply = NULL;
_cleanup_(link_info_clear) LinkInfo info = LINK_INFO_NULL;
uint16_t nlmsg_type;
int r;
assert(rtnl);
assert(ifindex > 0);
assert(ret);
if (!*rtnl) {
r = sd_netlink_open(rtnl);
if (r < 0)
return r;
}
r = sd_rtnl_message_new_link(*rtnl, &message, RTM_GETLINK, ifindex);
if (r < 0)
return r;
r = sd_netlink_call(*rtnl, message, 0, &reply);
if (r == -EINVAL)
return -ENODEV; /* The device does not exist */
if (r < 0)
return r;
r = sd_netlink_message_get_type(reply, &nlmsg_type);
if (r < 0)
return r;
if (nlmsg_type != RTM_NEWLINK)
return -ENXIO;
r = sd_rtnl_message_link_get_ifindex(reply, &info.ifindex);
if (r < 0)
return r;
if (info.ifindex != ifindex)
return -ENXIO;
r = sd_rtnl_message_link_get_type(reply, &info.iftype);
if (r < 0)
return r;
r = netlink_message_read_hw_addr(reply, IFLA_ADDRESS, &info.hw_addr);
if (r < 0 && r != -ENODATA)
return r;
r = sd_netlink_message_read_string_strdup(reply, IFLA_IFNAME, &info.ifname);
if (r < 0)
return r;
r = sd_netlink_message_read_u32(reply, IFLA_LINK, &info.iflink);
if (r == -ENODATA)
info.iflink = info.ifindex;
else if (r < 0)
return r;
r = sd_netlink_message_read_string_strdup(reply, IFLA_PHYS_PORT_NAME, &info.phys_port_name);
if (r == -ENODATA) {
uint16_t max_attr;
r = sd_netlink_message_get_max_attribute(reply, &max_attr);
if (r < 0)
return r;
info.support_phys_port_name = max_attr >= IFLA_PHYS_PORT_NAME;
} else if (r >= 0)
info.support_phys_port_name = true;
else
return r;
*ret = info;
info = LINK_INFO_NULL;
return 0;
}

View File

@ -0,0 +1,23 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "sd-netlink.h"
#include "ether-addr-util.h"
typedef struct LinkInfo {
int ifindex;
uint16_t iftype; /* ARPHRD_* */
struct hw_addr_data hw_addr; /* IFLA_ADDRESS */
char *ifname; /* IFLA_IFNAME */
uint32_t iflink; /* IFLA_LINK */
char *phys_port_name; /* IFLA_PHYS_PORT_NAME */
bool support_phys_port_name;
} LinkInfo;
#define LINK_INFO_NULL ((LinkInfo) {})
void link_info_clear(LinkInfo *info);
int link_info_get(sd_netlink **rtnl, int ifindex, LinkInfo *ret);

View File

@ -35,8 +35,8 @@
#include "string-util.h"
#include "strv.h"
#include "strxcpyx.h"
#include "udev-builtin-net_id-netlink.h"
#include "udev-builtin.h"
#include "udev-netlink.h"
#define ONBOARD_14BIT_INDEX_MAX ((1U << 14) - 1)
#define ONBOARD_16BIT_INDEX_MAX ((1U << 16) - 1)
@ -342,16 +342,22 @@ static int dev_pci_slot(sd_device *dev, const LinkInfo *info, NetNames *names) {
r = safe_atolu_full(attr, 10, &dev_port);
if (r < 0)
log_device_debug_errno(dev, r, "Failed to parse attribute dev_port, ignoring: %m");
/* With older kernels IP-over-InfiniBand network interfaces sometimes erroneously
* provide the port number in the 'dev_id' sysfs attribute instead of 'dev_port',
* which thus stays initialized as 0. */
if (dev_port == 0 &&
info->iftype == ARPHRD_INFINIBAND &&
sd_device_get_sysattr_value(dev, "dev_id", &attr) >= 0) {
r = safe_atolu_full(attr, 10, &dev_port);
sd_device_get_sysattr_value(dev, "type", &attr) >= 0) {
unsigned long type;
r = safe_atolu_full(attr, 10, &type);
if (r < 0)
log_device_debug_errno(dev, r, "Failed to parse attribute dev_id, ignoring: %m");
log_device_debug_errno(dev, r, "Failed to parse attribute type, ignoring: %m");
else if (type == ARPHRD_INFINIBAND &&
sd_device_get_sysattr_value(dev, "dev_id", &attr) >= 0) {
r = safe_atolu_full(attr, 10, &dev_port);
if (r < 0)
log_device_debug_errno(dev, r, "Failed to parse attribute dev_id, ignoring: %m");
}
}
}
@ -853,7 +859,7 @@ static int builtin_net_id(sd_device *dev, sd_netlink **rtnl, int argc, char *arg
if (r < 0)
return r;
if (!info.phys_port_name_supported) {
if (!info.support_phys_port_name) {
const char *s;
r = sd_device_get_sysattr_value(dev, "phys_port_name", &s);
@ -864,10 +870,6 @@ static int builtin_net_id(sd_device *dev, sd_netlink **rtnl, int argc, char *arg
}
}
r = device_cache_sysattr_from_link_info(dev, &info);
if (r < 0)
return r;
/* skip stacked devices, like VLANs, ... */
if (info.ifindex != (int) info.iflink)
return 0;

View File

@ -30,7 +30,6 @@
#include "strxcpyx.h"
#include "udev-builtin.h"
#include "udev-event.h"
#include "udev-netlink.h"
#include "udev-node.h"
#include "udev-util.h"
#include "udev-watch.h"
@ -352,11 +351,11 @@ static ssize_t udev_event_subst_format(
/* try to read the attribute the device */
if (!val)
(void) device_get_sysattr_value_maybe_from_netlink(dev, &event->rtnl, attr, &val);
(void) sd_device_get_sysattr_value(dev, attr, &val);
/* try to read the attribute of the parent device, other matches have selected */
if (!val && event->dev_parent && event->dev_parent != dev)
(void) device_get_sysattr_value_maybe_from_netlink(event->dev_parent, &event->rtnl, attr, &val);
(void) sd_device_get_sysattr_value(event->dev_parent, attr, &val);
if (!val)
goto null_terminate;

View File

@ -1,330 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "device-private.h"
#include "hexdecoct.h"
#include "netlink-util.h"
#include "strv.h"
#include "udev-netlink.h"
void link_info_clear(LinkInfo *info) {
if (!info)
return;
info->ifname = mfree(info->ifname);
info->ifalias = mfree(info->ifalias);
info->phys_port_id = mfree(info->phys_port_id);
info->phys_switch_id = mfree(info->phys_switch_id);
info->phys_port_name = mfree(info->phys_port_name);
}
int link_info_get(sd_netlink **rtnl, int ifindex, LinkInfo *ret) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL, *reply = NULL;
_cleanup_(link_info_clear) LinkInfo info = LINK_INFO_NULL;
uint16_t nlmsg_type, max_attr;
int r;
assert(rtnl);
assert(ifindex > 0);
assert(ret);
if (!*rtnl) {
r = sd_netlink_open(rtnl);
if (r < 0)
return r;
}
r = sd_rtnl_message_new_link(*rtnl, &message, RTM_GETLINK, ifindex);
if (r < 0)
return r;
r = sd_netlink_call(*rtnl, message, 0, &reply);
if (r == -EINVAL)
return -ENODEV; /* The device does not exist */
if (r < 0)
return r;
r = sd_netlink_message_get_type(reply, &nlmsg_type);
if (r < 0)
return r;
if (nlmsg_type != RTM_NEWLINK)
return -ENXIO;
r = sd_rtnl_message_link_get_ifindex(reply, &info.ifindex);
if (r < 0)
return r;
if (info.ifindex != ifindex)
return -ENXIO;
r = sd_rtnl_message_link_get_type(reply, &info.iftype);
if (r < 0)
return r;
r = netlink_message_read_hw_addr(reply, IFLA_ADDRESS, &info.hw_addr);
if (r < 0 && r != -ENODATA)
return r;
r = netlink_message_read_hw_addr(reply, IFLA_BROADCAST, &info.broadcast);
if (r < 0 && r != -ENODATA)
return r;
r = sd_netlink_message_read_string_strdup(reply, IFLA_IFNAME, &info.ifname);
if (r < 0)
return r;
r = sd_netlink_message_read_u32(reply, IFLA_MTU, &info.mtu);
if (r < 0)
return r;
r = sd_netlink_message_read_u32(reply, IFLA_LINK, &info.iflink);
if (r == -ENODATA)
info.iflink = info.ifindex;
else if (r < 0)
return r;
r = sd_netlink_message_read_u8(reply, IFLA_LINKMODE, &info.link_mode);
if (r < 0)
return r;
r = sd_netlink_message_read_string_strdup(reply, IFLA_IFALIAS, &info.ifalias);
if (r < 0 && r != -ENODATA)
return r;
r = sd_netlink_message_read_u32(reply, IFLA_GROUP, &info.group);
if (r < 0)
return r;
r = sd_netlink_message_read_data(reply, IFLA_PHYS_PORT_ID,
&info.phys_port_id_len, (void**) &info.phys_port_id);
if (r < 0 && r != -ENODATA)
return r;
r = sd_netlink_message_read_data(reply, IFLA_PHYS_SWITCH_ID,
&info.phys_switch_id_len, (void**) &info.phys_switch_id);
if (r < 0 && r != -ENODATA)
return r;
r = sd_netlink_message_read_string_strdup(reply, IFLA_PHYS_PORT_NAME, &info.phys_port_name);
if (r < 0 && r != -ENODATA)
return r;
r = sd_netlink_message_get_max_attribute(reply, &max_attr);
if (r < 0)
return r;
info.phys_port_id_supported = max_attr >= IFLA_PHYS_PORT_ID;
info.phys_switch_id_supported = max_attr >= IFLA_PHYS_SWITCH_ID;
info.phys_port_name_supported = max_attr >= IFLA_PHYS_PORT_NAME;
*ret = info;
info = LINK_INFO_NULL;
return 0;
}
static int cache_unsigned(sd_device *device, const char *attr, uint64_t val) {
_cleanup_free_ char *str = NULL;
int r;
assert(device);
assert(attr);
if (device_get_cached_sysattr_value(device, attr, NULL) != -ESTALE)
return 0;
if (asprintf(&str, "%"PRIu64, val) < 0)
return -ENOMEM;
r = device_cache_sysattr_value(device, attr, str);
if (r < 0)
return r;
TAKE_PTR(str);
return 0;
}
static int cache_hw_addr(sd_device *device, const char *attr, const struct hw_addr_data *hw_addr) {
_cleanup_free_ char *str = NULL;
int r;
assert(device);
assert(attr);
assert(hw_addr);
if (device_get_cached_sysattr_value(device, attr, NULL) != -ESTALE)
return 0;
str = new(char, HW_ADDR_TO_STRING_MAX);
if (!str)
return -ENOMEM;
r = device_cache_sysattr_value(device, attr, hw_addr_to_string(hw_addr, str));
if (r < 0)
return r;
TAKE_PTR(str);
return 0;
}
static int cache_binary(sd_device *device, const char *attr, size_t len, const uint8_t *data) {
_cleanup_free_ char *str = NULL;
int r;
assert(device);
assert(attr);
if (device_get_cached_sysattr_value(device, attr, NULL) != -ESTALE)
return 0;
if (data) {
size_t j = 0;
str = new(char, len * 2 + 1);
if (!str)
return -ENOMEM;
for (size_t i = 0; i < len; i++) {
str[j++] = hexchar(data[i] >> 4);
str[j++] = hexchar(data[i] & 0x0f);
}
str[j] = '\0';
}
r = device_cache_sysattr_value(device, attr, str);
if (r < 0)
return r;
TAKE_PTR(str);
return 0;
}
static int cache_string(sd_device *device, const char *attr, const char *val) {
_cleanup_free_ char *str = NULL;
int r;
assert(device);
assert(attr);
if (device_get_cached_sysattr_value(device, attr, NULL) != -ESTALE)
return 0;
if (val) {
str = strdup(val);
if (!str)
return -ENOMEM;
}
r = device_cache_sysattr_value(device, attr, str);
if (r < 0)
return r;
TAKE_PTR(str);
return 0;
}
int device_cache_sysattr_from_link_info(sd_device *device, LinkInfo *info) {
int ifindex, r;
assert(device);
assert(info);
r = sd_device_get_ifindex(device, &ifindex);
if (r < 0)
return r;
if (ifindex != info->ifindex)
return -EINVAL;
r = cache_unsigned(device, "type", info->iftype);
if (r < 0)
return r;
r = cache_unsigned(device, "addr_len", info->hw_addr.length);
if (r < 0)
return r;
r = cache_hw_addr(device, "address", &info->hw_addr);
if (r < 0)
return r;
r = cache_hw_addr(device, "broadcast", &info->broadcast);
if (r < 0)
return r;
r = cache_unsigned(device, "mtu", info->mtu);
if (r < 0)
return r;
r = cache_unsigned(device, "iflink", info->iflink);
if (r < 0)
return r;
r = cache_unsigned(device, "link_mode", info->link_mode);
if (r < 0)
return r;
r = cache_string(device, "ifalias", strempty(info->ifalias));
if (r < 0)
return r;
r = cache_unsigned(device, "netdev_group", info->group);
if (r < 0)
return r;
if (info->phys_port_id_supported) {
r = cache_binary(device, "phys_port_id", info->phys_port_id_len, info->phys_port_id);
if (r < 0)
return r;
}
if (info->phys_switch_id_supported) {
r = cache_binary(device, "phys_switch_id", info->phys_switch_id_len, info->phys_switch_id);
if (r < 0)
return r;
}
if (info->phys_port_name_supported) {
r = cache_string(device, "phys_port_name", info->phys_port_name);
if (r < 0)
return r;
}
return 0;
}
int device_get_sysattr_value_maybe_from_netlink(
sd_device *device,
sd_netlink **rtnl,
const char *sysattr,
const char **ret_value) {
_cleanup_(link_info_clear) LinkInfo info = LINK_INFO_NULL;
int ifindex, r;
assert(device);
assert(rtnl);
assert(sysattr);
if (sd_device_get_ifindex(device, &ifindex) < 0)
return sd_device_get_sysattr_value(device, sysattr, ret_value);
if (!STR_IN_SET(sysattr,
"type", "addr_len", "address", "broadcast", "mtu", "iflink", "linkmode",
"ifalias", "group", "phys_port_id", "phys_switch_id", "phys_port_name"))
return sd_device_get_sysattr_value(device, sysattr, ret_value);
r = device_get_cached_sysattr_value(device, sysattr, ret_value);
if (r != -ESTALE)
return r;
r = link_info_get(rtnl, ifindex, &info);
if (r < 0)
return r;
r = device_cache_sysattr_from_link_info(device, &info);
if (r < 0)
return r;
/* Do not use device_get_cached_sysattr_value() here, as kernel may not support
* IFLA_PHYS_PORT_NAME, and in that case we need to read the value from sysfs. */
return sd_device_get_sysattr_value(device, sysattr, ret_value);
}

View File

@ -1,41 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "sd-device.h"
#include "sd-netlink.h"
#include "ether-addr-util.h"
typedef struct LinkInfo {
int ifindex;
uint16_t iftype; /* ARPHRD_* (type) */
struct hw_addr_data hw_addr; /* IFLA_ADDRESS (address, addr_len) */
struct hw_addr_data broadcast; /* IFLA_BROADCAST (broadcast) */
char *ifname; /* IFLA_IFNAME */
uint32_t mtu; /* IFLA_MTU (mtu) */
uint32_t iflink; /* IFLA_LINK (iflink) */
uint8_t link_mode; /* IFLA_LINKMODE (link_mode) */
char *ifalias; /* IFLA_IFALIAS (ifalias) */
uint32_t group; /* IFLA_GROUP (netdev_group) */
uint8_t *phys_port_id; /* IFLA_PHYS_PORT_ID (phys_port_id) */
size_t phys_port_id_len;
uint8_t *phys_switch_id; /* IFLA_PHYS_SWITCH_ID (phys_switch_id) */
size_t phys_switch_id_len;
char *phys_port_name; /* IFLA_PHYS_PORT_NAME (phys_port_name) */
bool phys_port_id_supported;
bool phys_switch_id_supported;
bool phys_port_name_supported;
} LinkInfo;
#define LINK_INFO_NULL ((LinkInfo) {})
void link_info_clear(LinkInfo *info);
int link_info_get(sd_netlink **rtnl, int ifindex, LinkInfo *ret);
int device_cache_sysattr_from_link_info(sd_device *device, LinkInfo *info);
int device_get_sysattr_value_maybe_from_netlink(
sd_device *device,
sd_netlink **rtnl,
const char *sysattr,
const char **ret_value);

View File

@ -29,7 +29,6 @@
#include "syslog-util.h"
#include "udev-builtin.h"
#include "udev-event.h"
#include "udev-netlink.h"
#include "udev-rules.h"
#include "udev-util.h"
#include "user-util.h"
@ -1397,7 +1396,7 @@ static bool token_match_attr(UdevRuleToken *token, sd_device *dev, UdevEvent *ev
name = nbuf;
_fallthrough_;
case SUBST_TYPE_PLAIN:
if (device_get_sysattr_value_maybe_from_netlink(dev, &event->rtnl, name, &value) < 0)
if (sd_device_get_sysattr_value(dev, name, &value) < 0)
return false;
break;
case SUBST_TYPE_SUBSYS: