mirror of
https://github.com/systemd/systemd
synced 2026-03-30 19:54:51 +02:00
Compare commits
25 Commits
e4d294c46d
...
40258ae061
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
40258ae061 | ||
|
|
599be274c1 | ||
|
|
a6089431d5 | ||
|
|
b1967fb83a | ||
|
|
c19a51bec4 | ||
|
|
ccd25f41f5 | ||
|
|
2c7ec8203e | ||
|
|
a2236110c3 | ||
|
|
5cbe70af02 | ||
|
|
40091021c3 | ||
|
|
4f0cfa7741 | ||
|
|
64c590fb06 | ||
|
|
92828080fb | ||
|
|
6bfd44ee04 | ||
|
|
54ccd706ba | ||
|
|
1321f675e7 | ||
|
|
1c2ad7a66c | ||
|
|
e44b0fbce7 | ||
|
|
78ae4d449e | ||
|
|
552b1699e2 | ||
|
|
d9ea90598f | ||
|
|
6ebc6a4560 | ||
|
|
914ac555cd | ||
|
|
18b1137977 | ||
|
|
b63dd5aad8 |
@ -364,3 +364,10 @@ disk images with `--image=` or similar:
|
|||||||
against any of the certificates in `/etc/verity.d/*.crt` (and 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
|
directores in `/usr/lib/`, `/run`, …) or passed to the kernel for validation
|
||||||
against its built-in certificates.
|
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.
|
||||||
|
|||||||
@ -677,6 +677,18 @@
|
|||||||
of the current PCR state.</para></listitem>
|
of the current PCR state.</para></listitem>
|
||||||
</varlistentry>
|
</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>
|
<varlistentry>
|
||||||
<term><option>try-empty-password=</option></term>
|
<term><option>try-empty-password=</option></term>
|
||||||
|
|
||||||
@ -689,13 +701,9 @@
|
|||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><option>x-systemd.device-timeout=</option></term>
|
<term><option>x-systemd.device-timeout=</option></term>
|
||||||
|
|
||||||
<listitem><para>Specifies how long systemd should wait for a device to show up
|
<listitem><para>Specifies how long systemd should wait for a block device to show up before
|
||||||
before giving up on the entry. The argument is a time in seconds or explicitly
|
giving up on the entry. The argument is a time in seconds or explicitly specified units of
|
||||||
specified units of
|
<literal>s</literal>, <literal>min</literal>, <literal>h</literal>, <literal>ms</literal>.
|
||||||
<literal>s</literal>,
|
|
||||||
<literal>min</literal>,
|
|
||||||
<literal>h</literal>,
|
|
||||||
<literal>ms</literal>.
|
|
||||||
</para></listitem>
|
</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include "ether-addr-util.h"
|
#include "ether-addr-util.h"
|
||||||
|
#include "hexdecoct.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
|
|
||||||
@ -15,12 +16,13 @@ char* hw_addr_to_string(const struct hw_addr_data *addr, char buffer[HW_ADDR_TO_
|
|||||||
assert(buffer);
|
assert(buffer);
|
||||||
assert(addr->length <= HW_ADDR_MAX_SIZE);
|
assert(addr->length <= HW_ADDR_MAX_SIZE);
|
||||||
|
|
||||||
for (size_t i = 0; i < addr->length; i++) {
|
for (size_t i = 0, j = 0; i < addr->length; i++) {
|
||||||
sprintf(&buffer[3*i], "%02"PRIx8, addr->bytes[i]);
|
buffer[j++] = hexchar(addr->bytes[i] >> 4);
|
||||||
if (i < addr->length - 1)
|
buffer[j++] = hexchar(addr->bytes[i] & 0x0f);
|
||||||
buffer[3*i + 2] = ':';
|
buffer[j++] = ':';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buffer[addr->length > 0 ? addr->length * 3 - 1 : 0] = '\0';
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -547,12 +547,25 @@ int read_virtual_file_fd(int fd, size_t max_size, char **ret_contents, size_t *r
|
|||||||
return !truncated;
|
return !truncated;
|
||||||
}
|
}
|
||||||
|
|
||||||
int read_virtual_file(const char *filename, 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) {
|
||||||
|
|
||||||
_cleanup_close_ int fd = -1;
|
_cleanup_close_ int fd = -1;
|
||||||
|
|
||||||
assert(filename);
|
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
|
||||||
|
|
||||||
fd = open(filename, O_RDONLY | O_NOCTTY | O_CLOEXEC);
|
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);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
|
|||||||
@ -69,7 +69,10 @@ 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_fd(int fd, 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);
|
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);
|
||||||
|
}
|
||||||
static inline int read_full_virtual_file(const char *filename, 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);
|
return read_virtual_file(filename, SIZE_MAX, ret_contents, ret_size);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -119,62 +119,57 @@ int on_ac_power(void) {
|
|||||||
bool found_offline = false, found_online = false;
|
bool found_offline = false, found_online = false;
|
||||||
_cleanup_closedir_ DIR *d = NULL;
|
_cleanup_closedir_ DIR *d = NULL;
|
||||||
struct dirent *de;
|
struct dirent *de;
|
||||||
|
int r;
|
||||||
|
|
||||||
d = opendir("/sys/class/power_supply");
|
d = opendir("/sys/class/power_supply");
|
||||||
if (!d)
|
if (!d)
|
||||||
return errno == ENOENT ? true : -errno;
|
return errno == ENOENT ? true : -errno;
|
||||||
|
|
||||||
FOREACH_DIRENT(de, d, return -errno) {
|
FOREACH_DIRENT(de, d, return -errno) {
|
||||||
_cleanup_close_ int fd = -1, device = -1;
|
_cleanup_close_ int device_fd = -1;
|
||||||
char contents[6];
|
_cleanup_free_ char *contents = NULL;
|
||||||
ssize_t n;
|
unsigned v;
|
||||||
|
|
||||||
device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
device_fd = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC);
|
||||||
if (device < 0) {
|
if (device_fd < 0) {
|
||||||
if (IN_SET(errno, ENOENT, ENOTDIR))
|
if (IN_SET(errno, ENOENT, ENOTDIR))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
return -errno;
|
return -errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
fd = openat(device, "type", O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
r = read_virtual_file_at(device_fd, "type", SIZE_MAX, &contents, NULL);
|
||||||
if (fd < 0) {
|
if (r == -ENOENT)
|
||||||
if (errno == ENOENT)
|
continue;
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
delete_trailing_chars(contents, NEWLINE);
|
||||||
|
|
||||||
|
/* 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"))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
return -errno;
|
contents = mfree(contents);
|
||||||
}
|
|
||||||
|
|
||||||
n = read(fd, contents, sizeof(contents));
|
r = read_virtual_file_at(device_fd, "online", SIZE_MAX, &contents, NULL);
|
||||||
if (n < 0)
|
if (r == -ENOENT)
|
||||||
return -errno;
|
|
||||||
|
|
||||||
if (n != 6 || memcmp(contents, "Mains\n", 6))
|
|
||||||
continue;
|
continue;
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
safe_close(fd);
|
delete_trailing_chars(contents, NEWLINE);
|
||||||
fd = openat(device, "online", O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
|
||||||
if (fd < 0) {
|
|
||||||
if (errno == ENOENT)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
return -errno;
|
r = safe_atou(contents, &v);
|
||||||
}
|
if (r < 0)
|
||||||
|
return r;
|
||||||
n = read(fd, contents, sizeof(contents));
|
if (v > 0) /* At least 1 and 2 are defined as different types of 'online' */
|
||||||
if (n < 0)
|
|
||||||
return -errno;
|
|
||||||
|
|
||||||
if (n != 2 || contents[1] != '\n')
|
|
||||||
return -EIO;
|
|
||||||
|
|
||||||
if (contents[0] == '1') {
|
|
||||||
found_online = true;
|
found_online = true;
|
||||||
break;
|
|
||||||
} else if (contents[0] == '0')
|
|
||||||
found_offline = true;
|
|
||||||
else
|
else
|
||||||
return -EIO;
|
found_offline = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return found_online || !found_offline;
|
return found_online || !found_offline;
|
||||||
|
|||||||
@ -276,19 +276,6 @@ static int detect_vm_dmi(void) {
|
|||||||
#endif
|
#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 XENFEAT_dom0 11 /* xen/include/public/features.h */
|
||||||
#define PATH_FEATURES "/sys/hypervisor/properties/features"
|
#define PATH_FEATURES "/sys/hypervisor/properties/features"
|
||||||
/* Returns -errno, or 0 for domU, or 1 for dom0 */
|
/* Returns -errno, or 0 for domU, or 1 for dom0 */
|
||||||
@ -342,6 +329,26 @@ 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) {
|
static int detect_vm_hypervisor(void) {
|
||||||
_cleanup_free_ char *hvtype = NULL;
|
_cleanup_free_ char *hvtype = NULL;
|
||||||
int r;
|
int r;
|
||||||
@ -435,7 +442,8 @@ 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
|
* → 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
|
* 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.
|
* nested inside other VMs. Also check for Xen now, because Xen PV mode does not override CPUID when nested
|
||||||
|
* inside another hypervisor.
|
||||||
*
|
*
|
||||||
* → Second, try to detect from CPUID, this will report KVM for whatever software is used even if info in DMI is
|
* → Second, try to detect from CPUID, this will report KVM for whatever software is used even if info in DMI is
|
||||||
* overwritten.
|
* overwritten.
|
||||||
@ -457,6 +465,15 @@ int detect_vm(void) {
|
|||||||
else if (r != VIRTUALIZATION_NONE)
|
else if (r != VIRTUALIZATION_NONE)
|
||||||
goto finish;
|
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 */
|
/* Detect from CPUID */
|
||||||
r = detect_vm_cpuid();
|
r = detect_vm_cpuid();
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -476,20 +493,7 @@ int detect_vm(void) {
|
|||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* x86 xen will most likely be detected by cpuid. If not (most likely
|
/* Check high-level hypervisor sysfs file */
|
||||||
* 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();
|
r = detect_vm_hypervisor();
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
@ -511,18 +515,7 @@ int detect_vm(void) {
|
|||||||
return r;
|
return r;
|
||||||
|
|
||||||
finish:
|
finish:
|
||||||
/* x86 xen Dom0 is detected as XEN in hypervisor and maybe others.
|
if (r == VIRTUALIZATION_NONE && other)
|
||||||
* 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;
|
r = VIRTUALIZATION_VM_OTHER;
|
||||||
|
|
||||||
cached_found = r;
|
cached_found = r;
|
||||||
|
|||||||
147
src/boot/efi/initrd.c
Normal file
147
src/boot/efi/initrd.c
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
/* 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;
|
||||||
|
}
|
||||||
11
src/boot/efi/initrd.h
Normal file
11
src/boot/efi/initrd.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
/* 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);
|
||||||
@ -4,6 +4,7 @@
|
|||||||
#include <efilib.h>
|
#include <efilib.h>
|
||||||
|
|
||||||
#include "linux.h"
|
#include "linux.h"
|
||||||
|
#include "initrd.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
#ifdef __i386__
|
#ifdef __i386__
|
||||||
@ -28,21 +29,25 @@ static VOID linux_efi_handover(EFI_HANDLE image, struct boot_params *params) {
|
|||||||
handover(image, ST, params);
|
handover(image, ST, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
EFI_STATUS linux_exec(EFI_HANDLE image,
|
EFI_STATUS linux_exec(
|
||||||
CHAR8 *cmdline, UINTN cmdline_len,
|
EFI_HANDLE image,
|
||||||
UINTN linux_addr,
|
const CHAR8 *cmdline, UINTN cmdline_len,
|
||||||
UINTN initrd_addr, UINTN initrd_size) {
|
const VOID *linux_buffer,
|
||||||
|
const VOID *initrd_buffer, UINTN initrd_length) {
|
||||||
|
|
||||||
const struct boot_params *image_params;
|
const struct boot_params *image_params;
|
||||||
struct boot_params *boot_params;
|
struct boot_params *boot_params;
|
||||||
|
EFI_HANDLE initrd_handle = NULL;
|
||||||
EFI_PHYSICAL_ADDRESS addr;
|
EFI_PHYSICAL_ADDRESS addr;
|
||||||
UINT8 setup_sectors;
|
UINT8 setup_sectors;
|
||||||
EFI_STATUS err;
|
EFI_STATUS err;
|
||||||
|
|
||||||
assert(image);
|
assert(image);
|
||||||
assert(cmdline);
|
assert(cmdline || cmdline_len == 0);
|
||||||
|
assert(linux_buffer);
|
||||||
|
assert(initrd_buffer || initrd_length == 0);
|
||||||
|
|
||||||
image_params = (const struct boot_params *) linux_addr;
|
image_params = (const struct boot_params *) linux_buffer;
|
||||||
|
|
||||||
if (image_params->hdr.boot_flag != 0xAA55 ||
|
if (image_params->hdr.boot_flag != 0xAA55 ||
|
||||||
image_params->hdr.header != SETUP_MAGIC ||
|
image_params->hdr.header != SETUP_MAGIC ||
|
||||||
@ -65,7 +70,7 @@ EFI_STATUS linux_exec(EFI_HANDLE image,
|
|||||||
boot_params->hdr = image_params->hdr;
|
boot_params->hdr = image_params->hdr;
|
||||||
boot_params->hdr.type_of_loader = 0xff;
|
boot_params->hdr.type_of_loader = 0xff;
|
||||||
setup_sectors = image_params->hdr.setup_sects > 0 ? image_params->hdr.setup_sects : 4;
|
setup_sectors = image_params->hdr.setup_sects > 0 ? image_params->hdr.setup_sects : 4;
|
||||||
boot_params->hdr.code32_start = (UINT32)linux_addr + (setup_sectors + 1) * 512;
|
boot_params->hdr.code32_start = (UINT32) POINTER_TO_PHYSICAL_ADDRESS(linux_buffer) + (setup_sectors + 1) * 512;
|
||||||
|
|
||||||
if (cmdline) {
|
if (cmdline) {
|
||||||
addr = 0xA0000;
|
addr = 0xA0000;
|
||||||
@ -84,9 +89,21 @@ EFI_STATUS linux_exec(EFI_HANDLE image,
|
|||||||
boot_params->hdr.cmd_line_ptr = (UINT32) addr;
|
boot_params->hdr.cmd_line_ptr = (UINT32) addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
boot_params->hdr.ramdisk_image = (UINT32) initrd_addr;
|
/* Providing the initrd via LINUX_INITRD_MEDIA_GUID is only supported by Linux 5.8+ (5.7+ on ARM64).
|
||||||
boot_params->hdr.ramdisk_size = (UINT32) initrd_size;
|
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;
|
||||||
|
|
||||||
|
/* 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);
|
linux_efi_handover(image, boot_params);
|
||||||
|
(void) initrd_unregister(initrd_handle);
|
||||||
|
initrd_handle = NULL;
|
||||||
return EFI_LOAD_ERROR;
|
return EFI_LOAD_ERROR;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -84,7 +84,8 @@ struct boot_params {
|
|||||||
UINT8 _pad9[276];
|
UINT8 _pad9[276];
|
||||||
} _packed_;
|
} _packed_;
|
||||||
|
|
||||||
EFI_STATUS linux_exec(EFI_HANDLE image,
|
EFI_STATUS linux_exec(
|
||||||
CHAR8 *cmdline, UINTN cmdline_size,
|
EFI_HANDLE image,
|
||||||
UINTN linux_addr,
|
const CHAR8 *cmdline, UINTN cmdline_len,
|
||||||
UINTN initrd_addr, UINTN initrd_size);
|
const VOID *linux_buffer,
|
||||||
|
const VOID *initrd_buffer, UINTN initrd_length);
|
||||||
|
|||||||
@ -38,6 +38,7 @@ systemd_boot_sources = '''
|
|||||||
|
|
||||||
stub_sources = '''
|
stub_sources = '''
|
||||||
linux.c
|
linux.c
|
||||||
|
initrd.c
|
||||||
splash.c
|
splash.c
|
||||||
stub.c
|
stub.c
|
||||||
cpio.c
|
cpio.c
|
||||||
|
|||||||
@ -331,3 +331,12 @@ typedef struct tdEFI_TCG2_PROTOCOL {
|
|||||||
} EFI_TCG2;
|
} EFI_TCG2;
|
||||||
|
|
||||||
#endif
|
#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} }
|
||||||
|
|||||||
@ -249,7 +249,9 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = linux_exec(image, cmdline, cmdline_len, linux_base, initrd_base, initrd_size);
|
err = linux_exec(image, cmdline, cmdline_len,
|
||||||
|
PHYSICAL_ADDRESS_TO_POINTER(linux_base),
|
||||||
|
PHYSICAL_ADDRESS_TO_POINTER(initrd_base), initrd_size);
|
||||||
graphics_mode(FALSE);
|
graphics_mode(FALSE);
|
||||||
return log_error_status_stall(err, L"Execution of embedded linux image failed: %r", err);
|
return log_error_status_stall(err, L"Execution of embedded linux image failed: %r", err);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,6 +32,7 @@ int acquire_fido2_key(
|
|||||||
|
|
||||||
_cleanup_strv_free_erase_ char **pins = NULL;
|
_cleanup_strv_free_erase_ char **pins = NULL;
|
||||||
_cleanup_free_ void *loaded_salt = NULL;
|
_cleanup_free_ void *loaded_salt = NULL;
|
||||||
|
bool device_exists = false;
|
||||||
const char *salt;
|
const char *salt;
|
||||||
size_t salt_size;
|
size_t salt_size;
|
||||||
char *e;
|
char *e;
|
||||||
@ -89,13 +90,29 @@ int acquire_fido2_key(
|
|||||||
-ENOANO, /* needs pin */
|
-ENOANO, /* needs pin */
|
||||||
-ENOLCK)) /* pin incorrect */
|
-ENOLCK)) /* pin incorrect */
|
||||||
return r;
|
return r;
|
||||||
}
|
|
||||||
|
|
||||||
pins = strv_free_erase(pins);
|
device_exists = true; /* that a PIN is needed/wasn't correct means that we managed to
|
||||||
|
* talk to a device */
|
||||||
|
}
|
||||||
|
|
||||||
if (headless)
|
if (headless)
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(ENOPKG), "PIN querying disabled via 'headless' option. Use the '$PIN' environment variable.");
|
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);
|
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)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to ask for user password: %m");
|
return log_error_errno(r, "Failed to ask for user password: %m");
|
||||||
|
|||||||
@ -18,6 +18,7 @@
|
|||||||
#include "cryptsetup-util.h"
|
#include "cryptsetup-util.h"
|
||||||
#include "device-util.h"
|
#include "device-util.h"
|
||||||
#include "efi-loader.h"
|
#include "efi-loader.h"
|
||||||
|
#include "env-util.h"
|
||||||
#include "escape.h"
|
#include "escape.h"
|
||||||
#include "fileio.h"
|
#include "fileio.h"
|
||||||
#include "fs-util.h"
|
#include "fs-util.h"
|
||||||
@ -82,6 +83,7 @@ static char *arg_tpm2_device = NULL;
|
|||||||
static bool arg_tpm2_device_auto = false;
|
static bool arg_tpm2_device_auto = false;
|
||||||
static uint32_t arg_tpm2_pcr_mask = UINT32_MAX;
|
static uint32_t arg_tpm2_pcr_mask = UINT32_MAX;
|
||||||
static bool arg_headless = false;
|
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_cipher, freep);
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_hash, freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_hash, freep);
|
||||||
@ -409,7 +411,15 @@ static int parse_one_option(const char *option) {
|
|||||||
} else if (streq(option, "headless"))
|
} else if (streq(option, "headless"))
|
||||||
arg_headless = true;
|
arg_headless = true;
|
||||||
|
|
||||||
else if (!streq(option, "x-initrd.attach"))
|
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"))
|
||||||
log_warning("Encountered unknown /etc/crypttab option '%s', ignoring.", option);
|
log_warning("Encountered unknown /etc/crypttab option '%s', ignoring.", option);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -710,11 +720,25 @@ static char *make_bindname(const char *volume) {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int make_security_device_monitor(sd_event *event, sd_device_monitor **ret) {
|
static int make_security_device_monitor(
|
||||||
|
sd_event **ret_event,
|
||||||
|
sd_device_monitor **ret_monitor) {
|
||||||
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor = NULL;
|
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor = NULL;
|
||||||
|
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(ret);
|
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");
|
||||||
|
|
||||||
r = sd_device_monitor_new(&monitor);
|
r = sd_device_monitor_new(&monitor);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -732,13 +756,61 @@ static int make_security_device_monitor(sd_event *event, sd_device_monitor **ret
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to start device monitor: %m");
|
return log_error_errno(r, "Failed to start device monitor: %m");
|
||||||
|
|
||||||
*ret = TAKE_PTR(monitor);
|
*ret_event = TAKE_PTR(event);
|
||||||
|
*ret_monitor = TAKE_PTR(monitor);
|
||||||
return 0;
|
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) {
|
static bool libcryptsetup_plugins_support(void) {
|
||||||
#if HAVE_LIBCRYPTSETUP_PLUGINS
|
#if HAVE_LIBCRYPTSETUP_PLUGINS
|
||||||
return crypt_token_external_path() != NULL;
|
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();
|
||||||
#else
|
#else
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
@ -776,11 +848,11 @@ static int attach_luks2_by_fido2(
|
|||||||
void *usrptr,
|
void *usrptr,
|
||||||
uint32_t activation_flags) {
|
uint32_t activation_flags) {
|
||||||
|
|
||||||
int r = -EOPNOTSUPP;
|
|
||||||
#if HAVE_LIBCRYPTSETUP_PLUGINS
|
#if HAVE_LIBCRYPTSETUP_PLUGINS
|
||||||
char **p;
|
|
||||||
_cleanup_strv_free_erase_ char **pins = NULL;
|
|
||||||
AskPasswordFlags flags = ASK_PASSWORD_PUSH_CACHE | ASK_PASSWORD_ACCEPT_CACHED;
|
AskPasswordFlags flags = ASK_PASSWORD_PUSH_CACHE | ASK_PASSWORD_ACCEPT_CACHED;
|
||||||
|
_cleanup_strv_free_erase_ char **pins = NULL;
|
||||||
|
char **p;
|
||||||
|
int r;
|
||||||
|
|
||||||
r = crypt_activate_by_token_pin(cd, name, "systemd-fido2", CRYPT_ANY_TOKEN, NULL, 0, usrptr, activation_flags);
|
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 */
|
if (r > 0) /* returns unlocked keyslot id on success */
|
||||||
@ -803,6 +875,7 @@ static int attach_luks2_by_fido2(
|
|||||||
if (headless)
|
if (headless)
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(ENOPKG), "PIN querying disabled via 'headless' option. Use the '$PIN' environment variable.");
|
return log_error_errno(SYNTHETIC_ERRNO(ENOPKG), "PIN querying disabled via 'headless' option. Use the '$PIN' environment variable.");
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
pins = strv_free_erase(pins);
|
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);
|
r = ask_password_auto("Please enter security token PIN:", "drive-harddisk", NULL, "fido2-pin", "cryptsetup.fido2-pin", until, flags, &pins);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -817,22 +890,11 @@ static int attach_luks2_by_fido2(
|
|||||||
}
|
}
|
||||||
|
|
||||||
flags &= ~ASK_PASSWORD_ACCEPT_CACHED;
|
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);
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return r;
|
||||||
|
#else
|
||||||
|
return -EOPNOTSUPP;
|
||||||
#endif
|
#endif
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int attach_luks_or_plain_or_bitlk_by_fido2(
|
static int attach_luks_or_plain_or_bitlk_by_fido2(
|
||||||
@ -908,8 +970,6 @@ static int attach_luks_or_plain_or_bitlk_by_fido2(
|
|||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
bool processed = false;
|
|
||||||
|
|
||||||
if (use_libcryptsetup_plugin && !arg_fido2_cid) {
|
if (use_libcryptsetup_plugin && !arg_fido2_cid) {
|
||||||
r = attach_luks2_by_fido2(cd, name, until, arg_headless, arg_fido2_device, flags);
|
r = attach_luks2_by_fido2(cd, name, until, arg_headless, arg_fido2_device, flags);
|
||||||
if (IN_SET(r, -ENOTUNIQ, -ENXIO, -ENOENT))
|
if (IN_SET(r, -ENOTUNIQ, -ENXIO, -ENOENT))
|
||||||
@ -943,11 +1003,7 @@ static int attach_luks_or_plain_or_bitlk_by_fido2(
|
|||||||
|
|
||||||
assert(!event);
|
assert(!event);
|
||||||
|
|
||||||
r = sd_event_default(&event);
|
r = make_security_device_monitor(&event, &monitor);
|
||||||
if (r < 0)
|
|
||||||
return log_error_errno(r, "Failed to allocate event loop: %m");
|
|
||||||
|
|
||||||
r = make_security_device_monitor(event, &monitor);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -958,17 +1014,9 @@ static int attach_luks_or_plain_or_bitlk_by_fido2(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (;;) {
|
r = run_security_device_monitor(event, monitor);
|
||||||
/* 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)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to run event loop: %m");
|
return r;
|
||||||
if (r == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
processed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
log_debug("Got one or more potentially relevant udev events, rescanning FIDO2...");
|
log_debug("Got one or more potentially relevant udev events, rescanning FIDO2...");
|
||||||
}
|
}
|
||||||
@ -1004,9 +1052,10 @@ static int attach_luks2_by_pkcs11(
|
|||||||
bool headless,
|
bool headless,
|
||||||
uint32_t flags) {
|
uint32_t flags) {
|
||||||
|
|
||||||
int r = -EOPNOTSUPP;
|
|
||||||
#if HAVE_LIBCRYPTSETUP_PLUGINS
|
#if HAVE_LIBCRYPTSETUP_PLUGINS
|
||||||
if (!crypt_get_type(cd) || strcmp(crypt_get_type(cd), CRYPT_LUKS2))
|
int r;
|
||||||
|
|
||||||
|
if (!streq_ptr(crypt_get_type(cd), CRYPT_LUKS2))
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Automatic PKCS#11 metadata requires LUKS2 device.");
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Automatic PKCS#11 metadata requires LUKS2 device.");
|
||||||
|
|
||||||
systemd_pkcs11_plugin_params params = {
|
systemd_pkcs11_plugin_params params = {
|
||||||
@ -1018,8 +1067,11 @@ static int attach_luks2_by_pkcs11(
|
|||||||
r = crypt_activate_by_token_pin(cd, name, "systemd-pkcs11", CRYPT_ANY_TOKEN, NULL, 0, ¶ms, flags);
|
r = crypt_activate_by_token_pin(cd, name, "systemd-pkcs11", CRYPT_ANY_TOKEN, NULL, 0, ¶ms, flags);
|
||||||
if (r > 0) /* returns unlocked keyslot id on success */
|
if (r > 0) /* returns unlocked keyslot id on success */
|
||||||
r = 0;
|
r = 0;
|
||||||
#endif
|
|
||||||
return r;
|
return r;
|
||||||
|
#else
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static int attach_luks_or_plain_or_bitlk_by_pkcs11(
|
static int attach_luks_or_plain_or_bitlk_by_pkcs11(
|
||||||
@ -1071,8 +1123,6 @@ static int attach_luks_or_plain_or_bitlk_by_pkcs11(
|
|||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
bool processed = false;
|
|
||||||
|
|
||||||
if (use_libcryptsetup_plugin && arg_pkcs11_uri_auto)
|
if (use_libcryptsetup_plugin && arg_pkcs11_uri_auto)
|
||||||
r = attach_luks2_by_pkcs11(cd, name, friendly, until, arg_headless, flags);
|
r = attach_luks2_by_pkcs11(cd, name, friendly, until, arg_headless, flags);
|
||||||
else {
|
else {
|
||||||
@ -1098,11 +1148,7 @@ static int attach_luks_or_plain_or_bitlk_by_pkcs11(
|
|||||||
|
|
||||||
assert(!event);
|
assert(!event);
|
||||||
|
|
||||||
r = sd_event_default(&event);
|
r = make_security_device_monitor(&event, &monitor);
|
||||||
if (r < 0)
|
|
||||||
return log_error_errno(r, "Failed to allocate event loop: %m");
|
|
||||||
|
|
||||||
r = make_security_device_monitor(event, &monitor);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -1114,17 +1160,9 @@ static int attach_luks_or_plain_or_bitlk_by_pkcs11(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (;;) {
|
r = run_security_device_monitor(event, monitor);
|
||||||
/* 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)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to run event loop: %m");
|
return r;
|
||||||
if (r == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
processed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
log_debug("Got one or more potentially relevant udev events, rescanning PKCS#11...");
|
log_debug("Got one or more potentially relevant udev events, rescanning PKCS#11...");
|
||||||
}
|
}
|
||||||
@ -1159,11 +1197,24 @@ static int attach_luks_or_plain_or_bitlk_by_pkcs11(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int make_tpm2_device_monitor(sd_event *event, sd_device_monitor **ret) {
|
static int make_tpm2_device_monitor(
|
||||||
|
sd_event **ret_event,
|
||||||
|
sd_device_monitor **ret_monitor) {
|
||||||
|
|
||||||
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor = NULL;
|
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor = NULL;
|
||||||
|
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(ret);
|
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");
|
||||||
|
|
||||||
r = sd_device_monitor_new(&monitor);
|
r = sd_device_monitor_new(&monitor);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -1181,7 +1232,8 @@ static int make_tpm2_device_monitor(sd_event *event, sd_device_monitor **ret) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to start device monitor: %m");
|
return log_error_errno(r, "Failed to start device monitor: %m");
|
||||||
|
|
||||||
*ret = TAKE_PTR(monitor);
|
*ret_event = TAKE_PTR(event);
|
||||||
|
*ret_monitor = TAKE_PTR(monitor);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1238,8 +1290,6 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
|
|||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
bool processed = false;
|
|
||||||
|
|
||||||
if (key_file || key_data) {
|
if (key_file || key_data) {
|
||||||
/* If key data is specified, use that */
|
/* If key data is specified, use that */
|
||||||
|
|
||||||
@ -1343,11 +1393,7 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
|
|||||||
return log_notice_errno(SYNTHETIC_ERRNO(EAGAIN),
|
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.");
|
"No TPM2 hardware discovered and EFI bios indicates no support for it either, assuming TPM2-less system, falling back to traditional unocking.");
|
||||||
|
|
||||||
r = sd_event_default(&event);
|
r = make_tpm2_device_monitor(&event, &monitor);
|
||||||
if (r < 0)
|
|
||||||
return log_error_errno(r, "Failed to allocate event loop: %m");
|
|
||||||
|
|
||||||
r = make_tpm2_device_monitor(event, &monitor);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -1358,17 +1404,9 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (;;) {
|
r = run_security_device_monitor(event, monitor);
|
||||||
/* 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)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to run event loop: %m");
|
return r;
|
||||||
if (r == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
processed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
log_debug("Got one or more potentially relevant udev events, rescanning for TPM2...");
|
log_debug("Got one or more potentially relevant udev events, rescanning for TPM2...");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,13 +18,15 @@ 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_device_id(sd_device *device, const char **ret);
|
||||||
|
|
||||||
int device_get_devlink_priority(sd_device *device, int *priority);
|
int device_get_devlink_priority(sd_device *device, int *priority);
|
||||||
int device_get_watch_handle(sd_device *device);
|
int device_get_watch_handle(sd_device *device);
|
||||||
int device_get_devnode_mode(sd_device *device, mode_t *mode);
|
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_uid(sd_device *device, uid_t *uid);
|
||||||
int device_get_devnode_gid(sd_device *device, gid_t *gid);
|
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_seal(sd_device *device);
|
||||||
void device_set_is_initialized(sd_device *device);
|
void device_set_is_initialized(sd_device *device);
|
||||||
int device_set_watch_handle(sd_device *device, int wd);
|
int device_set_watch_handle(sd_device *device, int wd);
|
||||||
|
|||||||
@ -1941,7 +1941,7 @@ _public_ int sd_device_get_trigger_uuid(sd_device *device, sd_id128_t *ret) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int device_cache_sysattr_value(sd_device *device, const char *key, char *value) {
|
int device_cache_sysattr_value(sd_device *device, const char *key, char *value) {
|
||||||
_unused_ _cleanup_free_ char *old_value = NULL;
|
_unused_ _cleanup_free_ char *old_value = NULL;
|
||||||
_cleanup_free_ char *new_key = NULL;
|
_cleanup_free_ char *new_key = NULL;
|
||||||
int r;
|
int r;
|
||||||
@ -1969,18 +1969,19 @@ static int device_cache_sysattr_value(sd_device *device, const char *key, char *
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int device_get_cached_sysattr_value(sd_device *device, const char *_key, const char **_value) {
|
int device_get_cached_sysattr_value(sd_device *device, const char *key, const char **ret_value) {
|
||||||
const char *key = NULL, *value;
|
const char *k = NULL, *value;
|
||||||
|
|
||||||
assert(device);
|
assert(device);
|
||||||
assert(_key);
|
assert(key);
|
||||||
|
|
||||||
value = hashmap_get2(device->sysattr_values, _key, (void **) &key);
|
value = hashmap_get2(device->sysattr_values, key, (void **) &k);
|
||||||
if (!key)
|
if (!k)
|
||||||
return -ENOENT;
|
return -ESTALE; /* We have not read the attribute. */
|
||||||
|
if (!value)
|
||||||
if (_value)
|
return -ENOENT; /* We have looked up the attribute before and it did not exist. */
|
||||||
*_value = value;
|
if (ret_value)
|
||||||
|
*ret_value = value;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1988,7 +1989,7 @@ static int device_get_cached_sysattr_value(sd_device *device, const char *_key,
|
|||||||
* with a NULL value in the cache, otherwise the returned string is stored */
|
* 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) {
|
_public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **ret_value) {
|
||||||
_cleanup_free_ char *value = NULL;
|
_cleanup_free_ char *value = NULL;
|
||||||
const char *path, *syspath, *cached_value = NULL;
|
const char *path, *syspath;
|
||||||
struct stat statbuf;
|
struct stat statbuf;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -1996,21 +1997,10 @@ _public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr,
|
|||||||
assert_return(sysattr, -EINVAL);
|
assert_return(sysattr, -EINVAL);
|
||||||
|
|
||||||
/* look for possibly already cached result */
|
/* look for possibly already cached result */
|
||||||
r = device_get_cached_sysattr_value(device, sysattr, &cached_value);
|
r = device_get_cached_sysattr_value(device, sysattr, ret_value);
|
||||||
if (r != -ENOENT) {
|
if (r != -ESTALE)
|
||||||
if (r < 0)
|
|
||||||
return r;
|
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);
|
r = sd_device_get_syspath(device, &syspath);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|||||||
@ -12,6 +12,7 @@
|
|||||||
#include "memory-util.h"
|
#include "memory-util.h"
|
||||||
#include "random-util.h"
|
#include "random-util.h"
|
||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
|
#include "unistd.h"
|
||||||
|
|
||||||
static void *libfido2_dl = NULL;
|
static void *libfido2_dl = NULL;
|
||||||
|
|
||||||
@ -1077,3 +1078,52 @@ finish:
|
|||||||
"FIDO2 tokens not supported on this build.");
|
"FIDO2 tokens not supported on this build.");
|
||||||
#endif
|
#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
|
||||||
|
}
|
||||||
|
|||||||
@ -119,3 +119,5 @@ int fido2_generate_hmac_hash(
|
|||||||
|
|
||||||
int fido2_list_devices(void);
|
int fido2_list_devices(void);
|
||||||
int fido2_find_device_auto(char **ret);
|
int fido2_find_device_auto(char **ret);
|
||||||
|
|
||||||
|
int fido2_have_device(const char *device);
|
||||||
|
|||||||
@ -33,12 +33,12 @@ libudevd_core_sources = '''
|
|||||||
udev-builtin-hwdb.c
|
udev-builtin-hwdb.c
|
||||||
udev-builtin-input_id.c
|
udev-builtin-input_id.c
|
||||||
udev-builtin-keyboard.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_id.c
|
||||||
udev-builtin-net_setup_link.c
|
udev-builtin-net_setup_link.c
|
||||||
udev-builtin-path_id.c
|
udev-builtin-path_id.c
|
||||||
udev-builtin-usb_id.c
|
udev-builtin-usb_id.c
|
||||||
|
udev-netlink.c
|
||||||
|
udev-netlink.h
|
||||||
net/link-config.c
|
net/link-config.c
|
||||||
net/link-config.h
|
net/link-config.h
|
||||||
'''.split()
|
'''.split()
|
||||||
@ -212,9 +212,9 @@ tests += [
|
|||||||
[threads,
|
[threads,
|
||||||
libacl]],
|
libacl]],
|
||||||
|
|
||||||
[['src/udev/test-udev-builtin-net_id-netlink.c',
|
[['src/udev/test-udev-netlink.c',
|
||||||
'src/udev/udev-builtin-net_id-netlink.c',
|
'src/udev/udev-netlink.c',
|
||||||
'src/udev/udev-builtin-net_id-netlink.h']],
|
'src/udev/udev-netlink.h']],
|
||||||
|
|
||||||
[['src/udev/fido_id/test-fido-id-desc.c',
|
[['src/udev/fido_id/test-fido-id-desc.c',
|
||||||
'src/udev/fido_id/fido_id_desc.c']],
|
'src/udev/fido_id/fido_id_desc.c']],
|
||||||
|
|||||||
@ -1,85 +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-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;
|
|
||||||
}
|
|
||||||
165
src/udev/test-udev-netlink.c
Normal file
165
src/udev/test-udev-netlink.c
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
/* 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;
|
||||||
|
}
|
||||||
@ -1,87 +0,0 @@
|
|||||||
/* 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;
|
|
||||||
}
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
/* 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);
|
|
||||||
@ -35,8 +35,8 @@
|
|||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
#include "strxcpyx.h"
|
#include "strxcpyx.h"
|
||||||
#include "udev-builtin-net_id-netlink.h"
|
|
||||||
#include "udev-builtin.h"
|
#include "udev-builtin.h"
|
||||||
|
#include "udev-netlink.h"
|
||||||
|
|
||||||
#define ONBOARD_14BIT_INDEX_MAX ((1U << 14) - 1)
|
#define ONBOARD_14BIT_INDEX_MAX ((1U << 14) - 1)
|
||||||
#define ONBOARD_16BIT_INDEX_MAX ((1U << 16) - 1)
|
#define ONBOARD_16BIT_INDEX_MAX ((1U << 16) - 1)
|
||||||
@ -342,24 +342,18 @@ static int dev_pci_slot(sd_device *dev, const LinkInfo *info, NetNames *names) {
|
|||||||
r = safe_atolu_full(attr, 10, &dev_port);
|
r = safe_atolu_full(attr, 10, &dev_port);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_device_debug_errno(dev, r, "Failed to parse attribute dev_port, ignoring: %m");
|
log_device_debug_errno(dev, r, "Failed to parse attribute dev_port, ignoring: %m");
|
||||||
|
|
||||||
/* With older kernels IP-over-InfiniBand network interfaces sometimes erroneously
|
/* With older kernels IP-over-InfiniBand network interfaces sometimes erroneously
|
||||||
* provide the port number in the 'dev_id' sysfs attribute instead of 'dev_port',
|
* provide the port number in the 'dev_id' sysfs attribute instead of 'dev_port',
|
||||||
* which thus stays initialized as 0. */
|
* which thus stays initialized as 0. */
|
||||||
if (dev_port == 0 &&
|
if (dev_port == 0 &&
|
||||||
sd_device_get_sysattr_value(dev, "type", &attr) >= 0) {
|
info->iftype == ARPHRD_INFINIBAND &&
|
||||||
unsigned long type;
|
|
||||||
|
|
||||||
r = safe_atolu_full(attr, 10, &type);
|
|
||||||
if (r < 0)
|
|
||||||
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) {
|
sd_device_get_sysattr_value(dev, "dev_id", &attr) >= 0) {
|
||||||
r = safe_atolu_full(attr, 10, &dev_port);
|
r = safe_atolu_full(attr, 10, &dev_port);
|
||||||
if (r < 0)
|
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 dev_id, ignoring: %m");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* compose a name based on the raw kernel's PCI bus, slot numbers */
|
/* compose a name based on the raw kernel's PCI bus, slot numbers */
|
||||||
s = names->pci_path;
|
s = names->pci_path;
|
||||||
@ -859,7 +853,7 @@ static int builtin_net_id(sd_device *dev, sd_netlink **rtnl, int argc, char *arg
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (!info.support_phys_port_name) {
|
if (!info.phys_port_name_supported) {
|
||||||
const char *s;
|
const char *s;
|
||||||
|
|
||||||
r = sd_device_get_sysattr_value(dev, "phys_port_name", &s);
|
r = sd_device_get_sysattr_value(dev, "phys_port_name", &s);
|
||||||
@ -870,6 +864,10 @@ 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, ... */
|
/* skip stacked devices, like VLANs, ... */
|
||||||
if (info.ifindex != (int) info.iflink)
|
if (info.ifindex != (int) info.iflink)
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@ -30,6 +30,7 @@
|
|||||||
#include "strxcpyx.h"
|
#include "strxcpyx.h"
|
||||||
#include "udev-builtin.h"
|
#include "udev-builtin.h"
|
||||||
#include "udev-event.h"
|
#include "udev-event.h"
|
||||||
|
#include "udev-netlink.h"
|
||||||
#include "udev-node.h"
|
#include "udev-node.h"
|
||||||
#include "udev-util.h"
|
#include "udev-util.h"
|
||||||
#include "udev-watch.h"
|
#include "udev-watch.h"
|
||||||
@ -351,11 +352,11 @@ static ssize_t udev_event_subst_format(
|
|||||||
|
|
||||||
/* try to read the attribute the device */
|
/* try to read the attribute the device */
|
||||||
if (!val)
|
if (!val)
|
||||||
(void) sd_device_get_sysattr_value(dev, attr, &val);
|
(void) device_get_sysattr_value_maybe_from_netlink(dev, &event->rtnl, attr, &val);
|
||||||
|
|
||||||
/* try to read the attribute of the parent device, other matches have selected */
|
/* try to read the attribute of the parent device, other matches have selected */
|
||||||
if (!val && event->dev_parent && event->dev_parent != dev)
|
if (!val && event->dev_parent && event->dev_parent != dev)
|
||||||
(void) sd_device_get_sysattr_value(event->dev_parent, attr, &val);
|
(void) device_get_sysattr_value_maybe_from_netlink(event->dev_parent, &event->rtnl, attr, &val);
|
||||||
|
|
||||||
if (!val)
|
if (!val)
|
||||||
goto null_terminate;
|
goto null_terminate;
|
||||||
|
|||||||
330
src/udev/udev-netlink.c
Normal file
330
src/udev/udev-netlink.c
Normal file
@ -0,0 +1,330 @@
|
|||||||
|
/* 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);
|
||||||
|
}
|
||||||
41
src/udev/udev-netlink.h
Normal file
41
src/udev/udev-netlink.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/* 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);
|
||||||
@ -29,6 +29,7 @@
|
|||||||
#include "syslog-util.h"
|
#include "syslog-util.h"
|
||||||
#include "udev-builtin.h"
|
#include "udev-builtin.h"
|
||||||
#include "udev-event.h"
|
#include "udev-event.h"
|
||||||
|
#include "udev-netlink.h"
|
||||||
#include "udev-rules.h"
|
#include "udev-rules.h"
|
||||||
#include "udev-util.h"
|
#include "udev-util.h"
|
||||||
#include "user-util.h"
|
#include "user-util.h"
|
||||||
@ -1396,7 +1397,7 @@ static bool token_match_attr(UdevRuleToken *token, sd_device *dev, UdevEvent *ev
|
|||||||
name = nbuf;
|
name = nbuf;
|
||||||
_fallthrough_;
|
_fallthrough_;
|
||||||
case SUBST_TYPE_PLAIN:
|
case SUBST_TYPE_PLAIN:
|
||||||
if (sd_device_get_sysattr_value(dev, name, &value) < 0)
|
if (device_get_sysattr_value_maybe_from_netlink(dev, &event->rtnl, name, &value) < 0)
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
case SUBST_TYPE_SUBSYS:
|
case SUBST_TYPE_SUBSYS:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user