* homed: as an extension to the directory+subvolume backend: if located on
especially marked fs, then sync down password into LUKS header of that fs,
and always verify passwords against it too. Bootstrapping is a problem
- though: if noone is logged in (or no other user even exists yet), how do you
+ though: if no one is logged in (or no other user even exists yet), how do you
unlock the volume in order to create the first user and add the first pw.
* homed: support new FS_IOC_ADD_ENCRYPTION_KEY ioctl for setting up fscrypt
See [Testing systemd using sanitizers](https://systemd.io/TESTING_WITH_SANITIZERS)
for more information.
+16. Fossies provides [source code misspelling reports](https://fossies.org/features.html#codespell).
+ The systemd report can be found [here](https://fossies.org/linux/test/systemd-master.tar.gz/codespell.html).
+
Access to Coverity and oss-fuzz reports is limited. Please reach out to the
maintainers if you need access.
sensor:modalias:acpi:BOSC0200*:dmi:*svn*Acer*:*pn*Spin*SP111-33*
ACCEL_MOUNT_MATRIX=0, 1, 0; 1, 0, 0; 0, 0, 1
+sensor:modalias:acpi:BOSC0200*:dmi:*svnAcer*:*pnSpinSP111-34*
+ ACCEL_MOUNT_MATRIX=0, 1, 0; 1, 0, 0; 0, 0, 1
+
#########################################
# Archos
#########################################
# MOUSE_WHEEL_CLICK_ANGLE_HORIZONTAL
# MOUSE_WHEEL_CLICK_COUNT
# MOUSE_WHEEL_CLICK_COUNT_HORIZONTAL
-# MOUSE_WHEEL_TILT_HORIZONTAL
-# MOUSE_WHEEL_TILT_VERTICAL
#
#########################################
# ID_INPUT_TRACKBALL #
# MOUSE_WHEEL_CLICK_COUNT_HORIZONTAL works the same way but also follows the
# rules of MOUSE_WHEEL_CLICK_ANGLE_HORIZONTAL.
-#########################################
-# MOUSE_WHEEL_TILT_HORIZONTAL #
-# MOUSE_WHEEL_TILT_VERTICAL #
-#########################################
-#
-# Indicates that the respective axis is not a mouse wheel rotation but a
-# tilt along that axis. Wheel tilt is most commonly used for horizontal
-# scroll wheel emulation on mice with only a single vertical wheel.
-#
-# The vertical and horizontal Axes are independently marked as tilt axes,
-# for example it is permitted to have a MOUSE_WHEEL_CLICK_COUNT or
-# MOUSE_WHEEL_CLICK_ANGLE for the vertical axis and mark the horizontal axis
-# marked as as MOUSE_WHEEL_TILT_HORIZONTAL.
-#
-# It is a bug to have either CLICK_COUNT or CLICK_ANGLE set on the same axis
-# as WHEEL_TILT. Applications should give priority to WHEEL_TILT and ignore
-# other settings.
-#
-# This is a flag only, permitted values: 0 or 1
-
#
# Sort by brand, type (usb, bluetooth), DPI, frequency.
# For mice with switchable resolution, sort by the starred entry.
('ID_INPUT_TOUCHPAD', Literal('1')),
('ID_INPUT_TOUCHSCREEN', Literal('1')),
('ID_INPUT_TRACKBALL', Literal('1')),
- ('MOUSE_WHEEL_TILT_HORIZONTAL', Literal('1')),
- ('MOUSE_WHEEL_TILT_VERTICAL', Literal('1')),
('POINTINGSTICK_SENSITIVITY', INTEGER),
('POINTINGSTICK_CONST_ACCEL', REAL),
('ID_INPUT_JOYSTICK_INTEGRATION', Or(('internal', 'external'))),
<literal>cifs</literal>. For details about these options, see
<citerefentry><refentrytitle>homectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>. If not
configured or assigned the empty string, the default storage is automatically determined: if not
- running in a container enviroment and <filename>/home/</filename> is not itself encrypted, defaults
+ running in a container environment and <filename>/home/</filename> is not itself encrypted, defaults
to <literal>luks</literal>. Otherwise defaults to <literal>subvolume</literal> if
<filename>/home/</filename> is on a btrfs file system, and <literal>directory</literal>
otherwise. Note that the storage selected on the <command>homectl</command> command line always takes
memory as is needed.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>RuntimeDirectoryInodesMax=</varname></term>
+
+ <listitem><para>Sets the limit on number of inodes for the
+ <varname>$XDG_RUNTIME_DIR</varname> runtime directory for each
+ user who logs in. Takes a number, optionally suffixed with the
+ usual K, G, M, and T suffixes, to the base 1024 (IEC).
+ Defaults to <varname>RuntimeDirectorySize=</varname> divided
+ by 4096. Note that this size is a safety limit only.
+ As each runtime directory is a tmpfs file system, it will
+ only consume as much memory as is needed.</para></listitem>
+ </varlistentry>
+
<varlistentry>
<term><varname>InhibitorsMax=</varname></term>
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly t RuntimeDirectorySize = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+ readonly t RuntimeDirectoryInodesMax = ...;
+ @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly t InhibitorsMax = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly t NCurrentInhibitors = ...;
<variablelist class="dbus-property" generated="True" extra-ref="RuntimeDirectorySize"/>
+ <variablelist class="dbus-property" generated="True" extra-ref="RuntimeDirectoryInodesMax"/>
+
<variablelist class="dbus-property" generated="True" extra-ref="InhibitorsMax"/>
<variablelist class="dbus-property" generated="True" extra-ref="NCurrentInhibitors"/>
<varname>HandleLidSwitchExternalPower</varname>, <varname>HandleLidSwitchDocked</varname>,
<varname>IdleActionUSec</varname>, <varname>HoldoffTimeoutUSec</varname>,
<varname>RemoveIPC</varname>, <varname>RuntimeDirectorySize</varname>,
- <varname>InhibitorsMax</varname>, and <varname>SessionsMax</varname>.
+ <varname>RuntimeDirectoryInodesMax</varname>, <varname>InhibitorsMax</varname>, and
+ <varname>SessionsMax</varname>.
</para>
<para>The <varname>IdleHint</varname> property reflects the idle hint state of the system. If the
<para><function>sd_bus_default_flush_close()</function> is similar to
<function>sd_bus_flush_close_unref</function>, but does not take a bus pointer argument and
- instead iterates over any of the "default" busses opened by
+ instead iterates over any of the "default" buses opened by
<citerefentry><refentrytitle>sd_bus_default</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_default_user</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_default_system</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
and similar calls. <function>sd_bus_default_flush_close()</function> is particularly useful to
- clean up any busses opened using those calls before the program exits.</para>
+ clean up any buses opened using those calls before the program exits.</para>
</refsect1>
<refsect1>
want_tests = get_option('tests')
slow_tests = want_tests != 'false' and get_option('slow-tests')
+fuzz_tests = want_tests != 'false' and get_option('fuzz-tests')
install_tests = get_option('install-tests')
if add_languages('cpp', required : fuzzer_build)
if name != prev
if want_tests == 'false'
message('Not compiling @0@ because tests is set to false'.format(name))
- elif slow_tests
+ elif slow_tests or fuzz_tests
exe = custom_target(
name,
output : name,
'@OUTPUT@'],
build_by_default : true)
else
- message('Not compiling @0@ because slow-tests is set to false'.format(name))
+ message('Not compiling @0@ because slow-tests/fuzz-tests is set to false'.format(name))
endif
endif
prev = name
- if want_tests != 'false' and slow_tests
+ if want_tests != 'false' and (slow_tests or fuzz_tests)
test('@0@:@1@:@2@'.format(b, c, sanitizer),
env,
env : ['UBSAN_OPTIONS=print_stacktrace=1:print_summary=1:halt_on_error=1'],
description : 'enable extra tests with =unsafe')
option('slow-tests', type : 'boolean', value : 'false',
description : 'run the slow tests by default')
+option('fuzz-tests', type : 'boolean', value : 'false',
+ description : 'run the fuzzer regression tests by default')
option('install-tests', type : 'boolean', value : 'false',
description : 'install test executables')
KERNEL=="mmcblk[0-9]boot[0-9]", ENV{DEVTYPE}=="disk", ENV{ID_PATH}=="?*", SYMLINK+="disk/by-path/$env{ID_PATH}-boot%n"
KERNEL!="mmcblk[0-9]boot[0-9]", ENV{DEVTYPE}=="disk", ENV{ID_PATH}=="?*", SYMLINK+="disk/by-path/$env{ID_PATH}"
ENV{DEVTYPE}=="partition", ENV{ID_PATH}=="?*", SYMLINK+="disk/by-path/$env{ID_PATH}-part%n"
+# compatible links for ATA devices
+KERNEL!="mmcblk[0-9]boot[0-9]", ENV{DEVTYPE}=="disk", ENV{ID_PATH_ATA_COMPAT}=="?*", SYMLINK+="disk/by-path/$env{ID_PATH_ATA_COMPAT}"
+ENV{DEVTYPE}=="partition", ENV{ID_PATH_ATA_COMPAT}=="?*", SYMLINK+="disk/by-path/$env{ID_PATH_ATA_COMPAT}-part%n"
# legacy virtio-pci by-path links (deprecated)
KERNEL=="vd*[!0-9]", ENV{ID_PATH}=="pci-*", SYMLINK+="disk/by-path/virtio-$env{ID_PATH}"
SUBSYSTEM=="bluetooth", TAG+="systemd", ENV{SYSTEMD_ALIAS}+="/sys/subsystem/bluetooth/devices/%k"
SUBSYSTEM=="bluetooth", TAG+="systemd", ENV{SYSTEMD_WANTS}+="bluetooth.target", ENV{SYSTEMD_USER_WANTS}+="bluetooth.target"
+SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{ID_USB_INTERFACES}=="*:0b????:*", ENV{ID_SMARTCARD_READER}="1"
ENV{ID_SMARTCARD_READER}=="?*", TAG+="systemd", ENV{SYSTEMD_WANTS}+="smartcard.target", ENV{SYSTEMD_USER_WANTS}+="smartcard.target"
SUBSYSTEM=="sound", KERNEL=="card*", TAG+="systemd", ENV{SYSTEMD_WANTS}+="sound.target", ENV{SYSTEMD_USER_WANTS}+="sound.target"
openpgp:"Retrieve openpgp keys for an email"
query:"Resolve domain names, IPv4 and IPv6 addresses"
reset-server-features:"Flushes all feature level information the resolver has learned about specific servers"
- reset-statistics:"Resets the statistics counter show in statistics to zero"
+ reset-statistics:"Resets the statistics counter shown in statistics to zero"
revert:"Revert the per-interfce DNS configuration"
service:"Resolve DNS-SD and SRV services"
+ statistics:"Show resolver statistics"
status:"Show the global and per-link DNS settings currently in effect"
tlsa:"Query tlsa public keys stored as TLSA resource records"
)
'--service[Resolve services]' \
'--service-address=no[Do not resolve address for services]' \
'--service-txt=no[Do not resolve TXT records for services]' \
- '--openpgp[Query OpenPGP public key]' \
- '--tlsa[Query TLS public key]' \
'--cname=no[Do not follow CNAME redirects]' \
'--search=no[Do not use search domains]' \
- '--statistics[Show resolver statistics]' \
- '--reset-statistics[Reset resolver statistics]' \
'*::default: _resolvectl_commands'
goto fail;
}
+ if (FLAGS_SET(flags, WRITE_STRING_FILE_SYNC)) {
+ /* Sync the rename, too */
+ r = fsync_directory_of_file(fileno(f));
+ if (r < 0)
+ return r;
+ }
+
return 0;
fail:
* it. This isn't going to give you shred(1) semantics, but hopefully should be good enough
* for stuff backed by tmpfs at least.
*
- * Note that we only erase like this if the link count of the file is zero. If it is higer it
+ * Note that we only erase like this if the link count of the file is zero. If it is higher it
* is still linked by someone else and we'll leave it to them to remove it securely
* eventually! */
/* We parse the EFI variable first, because later settings have higher priority. */
- r = systemd_efi_options_variable(&line);
- if (r < 0 && r != -ENODATA)
- log_debug_errno(r, "Failed to get SystemdOptions EFI variable, ignoring: %m");
+ if (!FLAGS_SET(flags, PROC_CMDLINE_IGNORE_EFI_OPTIONS)) {
+ r = systemd_efi_options_variable(&line);
+ if (r < 0 && r != -ENODATA)
+ log_debug_errno(r, "Failed to get SystemdOptions EFI variable, ignoring: %m");
- r = proc_cmdline_parse_given(line, parse_item, data, flags);
- if (r < 0)
- return r;
+ r = proc_cmdline_parse_given(line, parse_item, data, flags);
+ if (r < 0)
+ return r;
+
+ line = mfree(line);
+ }
- line = mfree(line);
r = proc_cmdline(&line);
if (r < 0)
return r;
}
int proc_cmdline_get_key(const char *key, ProcCmdlineFlags flags, char **ret_value) {
- _cleanup_free_ char *line = NULL;
+ _cleanup_free_ char *line = NULL, *v = NULL;
int r;
/* Looks for a specific key on the kernel command line and (with lower priority) the EFI variable.
if (r < 0)
return r;
- r = cmdline_get_key(line, key, flags, ret_value);
- if (r != 0) /* Either error or true if found. */
+ if (FLAGS_SET(flags, PROC_CMDLINE_IGNORE_EFI_OPTIONS)) /* Shortcut */
+ return cmdline_get_key(line, key, flags, ret_value);
+
+ r = cmdline_get_key(line, key, flags, ret_value ? &v : NULL);
+ if (r < 0)
return r;
+ if (r > 0) {
+ if (ret_value)
+ *ret_value = TAKE_PTR(v);
+
+ return r;
+ }
line = mfree(line);
r = systemd_efi_options_variable(&line);
- if (r == -ENODATA)
+ if (r == -ENODATA) {
+ if (ret_value)
+ *ret_value = NULL;
+
return false; /* Not found */
+ }
if (r < 0)
return r;
int proc_cmdline_get_key_many_internal(ProcCmdlineFlags flags, ...) {
_cleanup_free_ char *line = NULL;
+ bool processing_efi = true;
const char *p;
va_list ap;
int r, ret = 0;
/* This call may clobber arguments on failure! */
- r = proc_cmdline(&line);
- if (r < 0)
- return r;
+ if (!FLAGS_SET(flags, PROC_CMDLINE_IGNORE_EFI_OPTIONS)) {
+ r = systemd_efi_options_variable(&line);
+ if (r < 0 && r != -ENODATA)
+ log_debug_errno(r, "Failed to get SystemdOptions EFI variable, ignoring: %m");
+ }
p = line;
for (;;) {
r = proc_cmdline_extract_first(&p, &word, flags);
if (r < 0)
return r;
- if (r == 0)
+ if (r == 0) {
+ /* We finished with this command line. If this was the EFI one, then let's proceed with the regular one */
+ if (processing_efi) {
+ processing_efi = false;
+
+ line = mfree(line);
+ r = proc_cmdline(&line);
+ if (r < 0)
+ return r;
+
+ p = line;
+ continue;
+ }
+
break;
+ }
va_start(ap, flags);
#include "log.h"
typedef enum ProcCmdlineFlags {
- PROC_CMDLINE_STRIP_RD_PREFIX = 1 << 0, /* automatically strip "rd." prefix if it is set (and we are in the initrd, since otherwise we'd not consider it anyway) */
- PROC_CMDLINE_VALUE_OPTIONAL = 1 << 1, /* the value is optional (for boolean switches that can omit the value) */
- PROC_CMDLINE_RD_STRICT = 1 << 2, /* ignore this in the initrd */
+ PROC_CMDLINE_STRIP_RD_PREFIX = 1 << 0, /* automatically strip "rd." prefix if it is set (and we are in the initrd, since otherwise we'd not consider it anyway) */
+ PROC_CMDLINE_VALUE_OPTIONAL = 1 << 1, /* the value is optional (for boolean switches that can omit the value) */
+ PROC_CMDLINE_RD_STRICT = 1 << 2, /* ignore this in the initrd */
+ PROC_CMDLINE_IGNORE_EFI_OPTIONS = 1 << 3, /* don't check systemd's private EFI variable */
} ProcCmdlineFlags;
typedef int (*proc_cmdline_parse_t)(const char *key, const char *value, void *data);
fn = strjoina("/var/lib/systemd/home/", h->user_name, ".identity");
- r = write_string_file(fn, text, WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MODE_0600);
+ r = write_string_file(fn, text, WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MODE_0600|WRITE_STRING_FILE_SYNC);
if (r < 0)
return r;
return sd_bus_error_setf(error, BUS_ERROR_HOME_NOT_ACTIVE, "Home %s is currently not active", h->user_name);
case -ENOSPC:
return sd_bus_error_setf(error, BUS_ERROR_NO_DISK_SPACE, "Not enough disk space for home %s", h->user_name);
+ case -EKEYREVOKED:
+ return sd_bus_error_setf(error, BUS_ERROR_HOME_CANT_AUTHENTICATE, "Home %s has no password or other authentication mechanism defined.", h->user_name);
}
return 0;
_cleanup_(user_record_unrefp) UserRecord *hr = NULL;
unsigned line, column;
int r, is_signed;
+ struct stat st;
Home *h;
assert(m);
assert(name);
assert(fname);
+ if (fstatat(dir_fd, fname, &st, 0) < 0)
+ return log_error_errno(errno, "Failed to stat identity record %s: %m", fname);
+
+ if (!S_ISREG(st.st_mode)) {
+ log_debug("Identity record file %s is not a regular file, ignoring.", fname);
+ return 0;
+ }
+
+ if (st.st_size == 0)
+ goto unlink_this_file;
+
r = json_parse_file_at(NULL, dir_fd, fname, JSON_PARSE_SENSITIVE, &v, &line, &column);
if (r < 0)
return log_error_errno(r, "Failed to parse identity record at %s:%u%u: %m", fname, line, column);
+ if (json_variant_is_blank_object(v))
+ goto unlink_this_file;
+
hr = user_record_new();
if (!hr)
return log_oom();
- r = user_record_load(hr, v, USER_RECORD_LOAD_REFUSE_SECRET);
+ r = user_record_load(hr, v, USER_RECORD_LOAD_REFUSE_SECRET|USER_RECORD_LOG);
if (r < 0)
return r;
h->signed_locally = is_signed == USER_RECORD_SIGNED_EXCLUSIVE;
return 1;
+
+unlink_this_file:
+ /* If this is an empty file, then let's just remove it. An empty file is not useful in any case, and
+ * apparently xfs likes to leave empty files around when not unmounted cleanly (see
+ * https://github.com/systemd/systemd/issues/15178 for example). Note that we don't delete non-empty
+ * files even if they are invalid, because that's just too risky, we might delete data the user still
+ * needs. But empty files are never useful, hence let's just remove them. */
+
+ if (unlinkat(dir_fd, fname, 0) < 0)
+ return log_error_errno(errno, "Failed to remove empty user record file %s: %m", fname);
+
+ log_notice("Discovered empty user record file /var/lib/systemd/home/%s, removed automatically.", fname);
+ return 0;
}
static int manager_enumerate_records(Manager *m) {
if (ERRNO_IS_NOT_SUPPORTED(r))
log_debug_errno(r, "No UID quota support on %s, ignoring.", where);
else
- log_warning_errno(r, "Failed to query quota on %s, ignoring.", where);
+ log_warning_errno(r, "Failed to query quota on %s, ignoring: %m", where);
continue;
}
if (PEM_write_PUBKEY(fpublic, m->private_key) <= 0)
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to write public key.");
- r = fflush_and_check(fpublic);
+ r = fflush_sync_and_check(fpublic);
if (r < 0)
return log_error_errno(r, "Failed to write private key: %m");
if (PEM_write_PrivateKey(fprivate, m->private_key, NULL, NULL, 0, NULL, 0) <= 0)
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to write private key pair.");
- r = fflush_and_check(fprivate);
+ r = fflush_sync_and_check(fprivate);
if (r < 0)
return log_error_errno(r, "Failed to write private key: %m");
if (rename(temp_private, "/var/lib/systemd/home/local.private") < 0) {
(void) unlink_noerrno("/var/lib/systemd/home/local.public"); /* try to remove the file we already created */
- return log_error_errno(errno, "Failed to move privtate key file into place: %m");
+ return log_error_errno(errno, "Failed to move private key file into place: %m");
}
temp_private = mfree(temp_private);
+ r = fsync_path_at(AT_FDCWD, "/var/lib/systemd/home/");
+ if (r < 0)
+ log_warning_errno(r, "Failed to sync /var/lib/systemd/home/, ignoring: %m");
+
return 1;
}
char **pw;
int r;
- r = home_unshare_and_mount(NULL, NULL, false);
+ r = home_unshare_and_mount(NULL, NULL, false, user_record_mount_flags(h));
if (r < 0)
return r;
if (!user_record_compatible(h, lhr))
return log_error_errno(SYNTHETIC_ERRNO(EREMCHG), "LUKS home record not compatible with host record, refusing.");
- r = user_record_authenticate(lhr, h, pkcs11_decrypted_passwords);
+ r = user_record_authenticate(lhr, h, pkcs11_decrypted_passwords, /* strict_verify= */ true);
if (r < 0)
return r;
+ assert(r > 0); /* Insist that a password was verified */
*ret_luks_home_record = TAKE_PTR(lhr);
return 0;
if (r < 0)
goto fail;
- r = home_unshare_and_mount(setup->dm_node, fstype, user_record_luks_discard(h));
+ r = home_unshare_and_mount(setup->dm_node, fstype, user_record_luks_discard(h), user_record_mount_flags(h));
if (r < 0)
goto fail;
log_info("Formatting file system completed.");
- r = home_unshare_and_mount(dm_node, fstype, user_record_luks_discard(h));
+ r = home_unshare_and_mount(dm_node, fstype, user_record_luks_discard(h), user_record_mount_flags(h));
if (r < 0)
goto fail;
return CAN_RESIZE_ONLINE;
}
-static int ext4_offline_resize_fs(HomeSetup *setup, uint64_t new_size, bool discard) {
+static int ext4_offline_resize_fs(HomeSetup *setup, uint64_t new_size, bool discard, unsigned long flags) {
_cleanup_free_ char *size_str = NULL;
bool re_open = false, re_mount = false;
pid_t resize_pid, fsck_pid;
/* Re-establish mounts and reopen the directory */
if (re_mount) {
- r = home_mount_node(setup->dm_node, "ext4", discard);
+ r = home_mount_node(setup->dm_node, "ext4", discard, flags);
if (r < 0)
return r;
if (resize_type == CAN_RESIZE_ONLINE)
r = resize_fs(setup->root_fd, new_fs_size, NULL);
else
- r = ext4_offline_resize_fs(setup, new_fs_size, user_record_luks_discard(h));
+ r = ext4_offline_resize_fs(setup, new_fs_size, user_record_luks_discard(h), user_record_mount_flags(h));
if (r < 0)
return log_error_errno(r, "Failed to resize file system: %m");
return NULL;
}
-int home_mount_node(const char *node, const char *fstype, bool discard) {
+int home_mount_node(const char *node, const char *fstype, bool discard, unsigned long flags) {
_cleanup_free_ char *joined = NULL;
const char *options, *discard_option;
int r;
} else
options = discard_option;
- r = mount_verbose(LOG_ERR, node, "/run/systemd/user-home-mount", fstype, MS_NODEV|MS_NOSUID|MS_RELATIME, strempty(options));
+ r = mount_verbose(LOG_ERR, node, "/run/systemd/user-home-mount", fstype, flags|MS_RELATIME, strempty(options));
if (r < 0)
return r;
return 0;
}
-int home_unshare_and_mount(const char *node, const char *fstype, bool discard) {
+int home_unshare_and_mount(const char *node, const char *fstype, bool discard, unsigned long flags) {
int r;
if (unshare(CLONE_NEWNS) < 0)
(void) mkdir_p("/run/systemd/user-home-mount", 0700);
if (node)
- return home_mount_node(node, fstype, discard);
+ return home_mount_node(node, fstype, discard, flags);
return 0;
}
#include <stdbool.h>
-int home_mount_node(const char *node, const char *fstype, bool discard);
-int home_unshare_and_mount(const char *node, const char *fstype, bool discard);
+int home_mount_node(const char *node, const char *fstype, bool discard, unsigned long flags);
+int home_unshare_and_mount(const char *node, const char *fstype, bool discard, unsigned long flags);
int home_move_mount(const char *user_name_and_realm, const char *target);
int user_record_authenticate(
UserRecord *h,
UserRecord *secret,
- char ***pkcs11_decrypted_passwords) {
+ char ***pkcs11_decrypted_passwords,
+ bool strict_verify) {
bool need_password = false, need_token = false, need_pin = false, need_protected_authentication_path_permitted = false,
pin_locked = false, pin_incorrect = false, pin_incorrect_few_tries_left = false, pin_incorrect_one_try_left = false;
return log_error_errno(r, "Failed to validate password of record: %m");
else {
log_info("Provided password unlocks user record.");
- return 0;
+ return 1;
}
/* Second, let's see if any of the PKCS#11 security tokens are plugged in and help us */
return log_error_errno(r, "Failed to check supplied PKCS#11 password: %m");
if (r > 0) {
log_info("Previously acquired PKCS#11 password unlocks user record.");
- return 0;
+ return 1;
}
}
if (r < 0)
return log_oom();
- return 0;
+ return 1;
}
#else
need_token = true;
return -ENOKEY;
/* Hmm, this means neither PCKS#11 nor classic hashed passwords were supplied, we cannot authenticate this reasonably */
- return log_debug_errno(SYNTHETIC_ERRNO(EKEYREVOKED), "No hashed passwords and no PKCS#11 tokens defined, cannot authenticate user record.");
+ if (strict_verify)
+ return log_debug_errno(SYNTHETIC_ERRNO(EKEYREVOKED),
+ "No hashed passwords and no PKCS#11 tokens defined, cannot authenticate user record, refusing.");
+
+ /* If strict verification is off this means we are possibly in the case where we encountered an
+ * unfixated record, i.e. a synthetic one that accordingly lacks any authentication data. In this
+ * case, allow the authentication to pass for now, so that the second (or third) authentication level
+ * (the ones of the user record in the LUKS header or inside the home directory) will then catch
+ * invalid passwords. The second/third authentication always runs in strict verification mode. */
+ log_debug("No hashed passwords and no PKCS#11 tokens defined in record, cannot authenticate user record. "
+ "Deferring to embedded user record.");
+ return 0;
}
int home_setup_undo(HomeSetup *setup) {
return log_error_errno(SYNTHETIC_ERRNO(EREMCHG), "Embedded home record not compatible with host record, refusing.");
/* Insist that credentials the user supplies also unlocks any embedded records. */
- r = user_record_authenticate(embedded_home, h, pkcs11_decrypted_passwords);
+ r = user_record_authenticate(embedded_home, h, pkcs11_decrypted_passwords, /* strict_verify= */ true);
if (r < 0)
return r;
+ assert(r > 0); /* Insist that a password was verified */
/* At this point we have three records to deal with:
*
if (!IN_SET(user_record_storage(h), USER_LUKS, USER_DIRECTORY, USER_SUBVOLUME, USER_FSCRYPT, USER_CIFS))
return log_error_errno(SYNTHETIC_ERRNO(ENOTTY), "Activating home directories of type '%s' currently not supported.", user_storage_to_string(user_record_storage(h)));
- r = user_record_authenticate(h, h, &pkcs11_decrypted_passwords);
+ r = user_record_authenticate(h, h, &pkcs11_decrypted_passwords, /* strict_verify= */ false);
if (r < 0)
return r;
assert(h);
assert(ret);
- r = user_record_authenticate(h, h, &pkcs11_decrypted_passwords);
+ r = user_record_authenticate(h, h, &pkcs11_decrypted_passwords, /* strict_verify= */ true);
if (r < 0)
return r;
+ assert(r > 0); /* Insist that a password was verified */
r = home_validate_update(h, &setup);
if (r < 0)
if (h->disk_size == UINT64_MAX)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No target size specified, refusing.");
- r = user_record_authenticate(h, h, &pkcs11_decrypted_passwords);
+ r = user_record_authenticate(h, h, &pkcs11_decrypted_passwords, /* strict_verify= */ true);
if (r < 0)
return r;
+ assert(r > 0); /* Insist that a password was verified */
r = home_validate_update(h, &setup);
if (r < 0)
assert(h);
assert(ret_home);
- r = user_record_authenticate(h, h, &pkcs11_decrypted_passwords);
+ r = user_record_authenticate(h, h, &pkcs11_decrypted_passwords, /* strict_verify= */ false);
if (r < 0)
return r;
/* Note that we don't check if $HOME is actually mounted, since we want to avoid disk accesses on
* that mount until we have resumed the device. */
- r = user_record_authenticate(h, h, &pkcs11_decrypted_passwords);
+ r = user_record_authenticate(h, h, &pkcs11_decrypted_passwords, /* strict_verify= */ false);
if (r < 0)
return r;
* EBUSY → file system is currently active
* ENOEXEC → file system is currently not active
* ENOSPC → not enough disk space for operation
+ * EKEYREVOKED → user record has not suitable hashed password or pkcs#11 entry, we cannot authenticate
*/
if (streq(argv[1], "activate"))
int home_store_embedded_identity(UserRecord *h, int root_fd, uid_t uid, UserRecord *old_home);
int home_extend_embedded_identity(UserRecord *h, UserRecord *used, HomeSetup *setup);
-int user_record_authenticate(UserRecord *h, UserRecord *secret, char ***pkcs11_decrypted_passwords);
+int user_record_authenticate(UserRecord *h, UserRecord *secret, char ***pkcs11_decrypted_passwords, bool strict_verify);
int home_sync_and_statfs(int root_fd, struct statfs *ret);
if (len >= (int)LONG_LINE_MAX - 8)
return -ENOBUFS;
- /* Allocate large buffer to accomodate big message */
+ /* Allocate large buffer to accommodate big message */
if (len >= LINE_MAX) {
int rlen;
buffer = alloca(len + 9);
if (len >= (int)LONG_LINE_MAX - 8)
return -ENOBUFS;
- /* Allocate large buffer to accomodate big message */
+ /* Allocate large buffer to accommodate big message */
if (len >= LINE_MAX) {
int rlen;
buffer = alloca(len + 9);
SD_BUS_ERROR_MAP(BUS_ERROR_HOME_NOT_LOCKED, ENOEXEC),
SD_BUS_ERROR_MAP(BUS_ERROR_TOO_MANY_OPERATIONS, ENOBUFS),
SD_BUS_ERROR_MAP(BUS_ERROR_AUTHENTICATION_LIMIT_HIT, ETOOMANYREFS),
+ SD_BUS_ERROR_MAP(BUS_ERROR_HOME_CANT_AUTHENTICATE, EKEYREVOKED),
SD_BUS_ERROR_MAP_END
};
#define BUS_ERROR_NO_DISK_SPACE "org.freedesktop.home1.NoDiskSpace"
#define BUS_ERROR_TOO_MANY_OPERATIONS "org.freedesktop.home1.TooManyOperations"
#define BUS_ERROR_AUTHENTICATION_LIMIT_HIT "org.freedesktop.home1.AuthenticationLimitHit"
+#define BUS_ERROR_HOME_CANT_AUTHENTICATE "org.freedesktop.home1.HomeCantAuthenticate"
BUS_ERROR_MAP_ELF_USE(bus_common_errors);
m->idle_action = HANDLE_IGNORE;
m->runtime_dir_size = physical_memory_scale(10U, 100U); /* 10% */
+ m->runtime_dir_inodes = DIV_ROUND_UP(m->runtime_dir_size, 4096); /* 4k per inode */
m->sessions_max = 8192;
m->inhibitors_max = 8192;
SD_BUS_PROPERTY("OnExternalPower", "b", property_get_on_external_power, 0, 0),
SD_BUS_PROPERTY("RemoveIPC", "b", bus_property_get_bool, offsetof(Manager, remove_ipc), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RuntimeDirectorySize", "t", NULL, offsetof(Manager, runtime_dir_size), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("RuntimeDirectoryInodesMax", "t", NULL, offsetof(Manager, runtime_dir_inodes), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("InhibitorsMax", "t", NULL, offsetof(Manager, inhibitors_max), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("NCurrentInhibitors", "t", property_get_hashmap_size, offsetof(Manager, inhibitors), 0),
SD_BUS_PROPERTY("SessionsMax", "t", NULL, offsetof(Manager, sessions_max), SD_BUS_VTABLE_PROPERTY_CONST),
Login.IdleAction, config_parse_handle_action, 0, offsetof(Manager, idle_action)
Login.IdleActionSec, config_parse_sec, 0, offsetof(Manager, idle_action_usec)
Login.RuntimeDirectorySize, config_parse_tmpfs_size, 0, offsetof(Manager, runtime_dir_size)
+Login.RuntimeDirectoryInodesMax, config_parse_uint64, 0, offsetof(Manager, runtime_dir_inodes)
Login.RemoveIPC, config_parse_bool, 0, offsetof(Manager, remove_ipc)
Login.InhibitorsMax, config_parse_uint64, 0, offsetof(Manager, inhibitors_max)
Login.SessionsMax, config_parse_uint64, 0, offsetof(Manager, sessions_max)
#IdleAction=ignore
#IdleActionSec=30min
#RuntimeDirectorySize=10%
+#RuntimeDirectoryInodes=400k
#RemoveIPC=yes
#InhibitorsMax=8192
#SessionsMax=8192
sd_event_source *lid_switch_ignore_event_source;
uint64_t runtime_dir_size;
+ uint64_t runtime_dir_inodes;
uint64_t sessions_max;
uint64_t inhibitors_max;
};
#include "strv.h"
#include "user-util.h"
-static int acquire_runtime_dir_size(uint64_t *ret) {
+static int acquire_runtime_dir_properties(uint64_t *size, uint64_t *inodes) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
int r;
if (r < 0)
return log_error_errno(r, "Failed to connect to system bus: %m");
- r = sd_bus_get_property_trivial(bus, "org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", "RuntimeDirectorySize", &error, 't', ret);
+ r = sd_bus_get_property_trivial(bus, "org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", "RuntimeDirectorySize", &error, 't', size);
if (r < 0)
return log_error_errno(r, "Failed to acquire runtime directory size: %s", bus_error_message(&error, r));
+ r = sd_bus_get_property_trivial(bus, "org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", "RuntimeDirectoryInodesMax", &error, 't', inodes);
+ if (r < 0)
+ return log_error_errno(r, "Failed to acquire number of inodes for runtime directory: %s", bus_error_message(&error, r));
+
return 0;
}
const char *runtime_path,
uid_t uid,
gid_t gid,
- uint64_t runtime_dir_size) {
+ uint64_t runtime_dir_size,
+ uint64_t runtime_dir_inodes) {
int r;
if (path_is_mount_point(runtime_path, NULL, 0) >= 0)
log_debug("%s is already a mount point", runtime_path);
else {
- char options[sizeof("mode=0700,uid=,gid=,size=,smackfsroot=*")
+ char options[sizeof("mode=0700,uid=,gid=,size=,nr_inodes=,smackfsroot=*")
+ DECIMAL_STR_MAX(uid_t)
+ DECIMAL_STR_MAX(gid_t)
+ + DECIMAL_STR_MAX(uint64_t)
+ DECIMAL_STR_MAX(uint64_t)];
xsprintf(options,
- "mode=0700,uid=" UID_FMT ",gid=" GID_FMT ",size=%" PRIu64 "%s",
- uid, gid, runtime_dir_size,
+ "mode=0700,uid=" UID_FMT ",gid=" GID_FMT ",size=%" PRIu64 ",nr_inodes=%" PRIu64 "%s",
+ uid, gid, runtime_dir_size, runtime_dir_inodes,
mac_smack_use() ? ",smackfsroot=*" : "");
(void) mkdir_label(runtime_path, 0700);
static int do_mount(const char *user) {
char runtime_path[sizeof("/run/user") + DECIMAL_STR_MAX(uid_t)];
- uint64_t runtime_dir_size;
+ uint64_t runtime_dir_size, runtime_dir_inodes;
uid_t uid;
gid_t gid;
int r;
: "Failed to look up user \"%s\": %m",
user);
- r = acquire_runtime_dir_size(&runtime_dir_size);
+ r = acquire_runtime_dir_properties(&runtime_dir_size, &runtime_dir_inodes);
if (r < 0)
return r;
xsprintf(runtime_path, "/run/user/" UID_FMT, uid);
log_debug("Will mount %s owned by "UID_FMT":"GID_FMT, runtime_path, uid, gid);
- return user_mkdir_runtime_path(runtime_path, uid, gid, runtime_dir_size);
+ return user_mkdir_runtime_path(runtime_path, uid, gid, runtime_dir_size, runtime_dir_inodes);
}
static int do_umount(const char *user) {
r = extract_first_word(&p, &word, ":", 0);
if (r == -ENOMEM)
return log_oom();
- if (r <= 0) {
+ if (r <= 0 || isempty(p)) {
log_syntax(unit, LOG_ERR, filename, line, r,
"Invalid DHCP option, ignoring assignment: %s", rvalue);
return 0;
DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
-/* For some reason we need some extra cmsg space on some kernels/archs. One of those days we ned to figure out why */
+/* For some reason we need some extra cmsg space on some kernels/archs. One of those days we need to figure out why */
#define EXTRA_CMSG_SPACE 1024
int manager_is_own_hostname(Manager *m, const char *name);
impl->path);
}
+ if (impl->manager) {
+ r = sd_bus_add_object_manager(bus, NULL, impl->path);
+ if (r < 0)
+ return log_error_errno(r, "Failed to add object manager for %s: %m", impl->path);
+ }
+
for (size_t i = 0; impl->children && impl->children[i]; i++) {
r = bus_add_implementation(bus, impl->children[i], userdata);
if (r < 0)
path_equal_ptr(path, p->runtime_control);
}
-static int path_is_vendor(const LookupPaths *p, const char *path) {
+static int path_is_vendor_or_generator(const LookupPaths *p, const char *path) {
const char *rpath;
assert(p);
return true;
#endif
+ if (path_is_generator(p, rpath))
+ return true;
+
return path_equal(rpath, SYSTEM_DATA_UNIT_PATH);
}
return -errno;
} else if (S_ISREG(st.st_mode)) {
/* Check if there's a vendor version */
- r = path_is_vendor(&paths, path);
+ r = path_is_vendor_or_generator(&paths, path);
if (r < 0)
return r;
if (r > 0)
return parent;
}
-static sd_device *handle_scsi_ata(sd_device *parent, char **path) {
+static sd_device *handle_scsi_ata(sd_device *parent, char **path, char **compat_path) {
sd_device *targetdev, *target_parent;
_cleanup_(sd_device_unrefp) sd_device *atadev = NULL;
- const char *port_no, *sysname;
+ const char *port_no, *sysname, *name;
+ unsigned host, bus, target, lun;
assert(parent);
assert(path);
+ if (sd_device_get_sysname(parent, &name) < 0)
+ return NULL;
+ if (sscanf(name, "%u:%u:%u:%u", &host, &bus, &target, &lun) != 4)
+ return NULL;
+
if (sd_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_host", &targetdev) < 0)
return NULL;
if (sd_device_get_sysattr_value(atadev, "port_no", &port_no) < 0)
return NULL;
- path_prepend(path, "ata-%s", port_no);
+ if (bus != 0)
+ /* Devices behind port multiplier have a bus != 0*/
+ path_prepend(path, "ata-%s.%u.0", port_no, bus);
+ else
+ /* Master/slave are distinguished by target id */
+ path_prepend(path, "ata-%s.%u", port_no, target);
+
+ /* old compatible persistent link for ATA devices */
+ if (compat_path)
+ path_prepend(compat_path, "ata-%s", port_no);
+
return parent;
}
return parent;
}
-static sd_device *handle_scsi(sd_device *parent, char **path, bool *supported_parent) {
+static sd_device *handle_scsi(sd_device *parent, char **path, char **compat_path, bool *supported_parent) {
const char *devtype, *id, *name;
if (sd_device_get_devtype(parent, &devtype) < 0 ||
}
if (strstr(name, "/ata"))
- return handle_scsi_ata(parent, path);
+ return handle_scsi_ata(parent, path, compat_path);
if (strstr(name, "/vmbus_"))
return handle_scsi_hyperv(parent, path, 37);
static int builtin_path_id(sd_device *dev, int argc, char *argv[], bool test) {
sd_device *parent;
_cleanup_free_ char *path = NULL;
+ _cleanup_free_ char *compat_path = NULL;
bool supported_transport = false;
bool supported_parent = false;
const char *subsystem;
} else if (streq(subsys, "scsi_tape")) {
handle_scsi_tape(parent, &path);
} else if (streq(subsys, "scsi")) {
- parent = handle_scsi(parent, &path, &supported_parent);
+ parent = handle_scsi(parent, &path, &compat_path, &supported_parent);
supported_transport = true;
} else if (streq(subsys, "cciss")) {
parent = handle_cciss(parent, &path);
}
} else if (streq(subsys, "pci")) {
path_prepend(&path, "pci-%s", sysname);
+ if (compat_path)
+ path_prepend(&compat_path, "pci-%s", sysname);
parent = skip_subsystem(parent, "pci");
supported_parent = true;
} else if (streq(subsys, "platform")) {
path_prepend(&path, "platform-%s", sysname);
+ if (compat_path)
+ path_prepend(&compat_path, "platform-%s", sysname);
parent = skip_subsystem(parent, "platform");
supported_transport = true;
supported_parent = true;
} else if (streq(subsys, "acpi")) {
path_prepend(&path, "acpi-%s", sysname);
+ if (compat_path)
+ path_prepend(&compat_path, "acpi-%s", sysname);
parent = skip_subsystem(parent, "acpi");
supported_parent = true;
} else if (streq(subsys, "xen")) {
path_prepend(&path, "xen-%s", sysname);
+ if (compat_path)
+ path_prepend(&compat_path, "xen-%s", sysname);
parent = skip_subsystem(parent, "xen");
supported_parent = true;
} else if (streq(subsys, "virtio")) {
supported_transport = true;
} else if (streq(subsys, "scm")) {
path_prepend(&path, "scm-%s", sysname);
+ if (compat_path)
+ path_prepend(&compat_path, "scm-%s", sysname);
parent = skip_subsystem(parent, "scm");
supported_transport = true;
supported_parent = true;
} else if (streq(subsys, "ccw")) {
path_prepend(&path, "ccw-%s", sysname);
+ if (compat_path)
+ path_prepend(&compat_path, "ccw-%s", sysname);
parent = skip_subsystem(parent, "ccw");
supported_transport = true;
supported_parent = true;
} else if (streq(subsys, "ccwgroup")) {
path_prepend(&path, "ccwgroup-%s", sysname);
+ if (compat_path)
+ path_prepend(&compat_path, "ccwgroup-%s", sysname);
parent = skip_subsystem(parent, "ccwgroup");
supported_transport = true;
supported_parent = true;
supported_parent = true;
} else if (streq(subsys, "iucv")) {
path_prepend(&path, "iucv-%s", sysname);
+ if (compat_path)
+ path_prepend(&compat_path, "iucv-%s", sysname);
parent = skip_subsystem(parent, "iucv");
supported_transport = true;
supported_parent = true;
if (sd_device_get_sysattr_value(dev, "nsid", &nsid) >= 0) {
path_prepend(&path, "nvme-%s", nsid);
+ if (compat_path)
+ path_prepend(&compat_path, "nvme-%s", nsid);
parent = skip_subsystem(parent, "nvme");
supported_parent = true;
supported_transport = true;
udev_builtin_add_property(dev, test, "ID_PATH_TAG", tag);
}
+ /*
+ * Compatible link generation for ATA devices
+ * we assign compat_link to the env variable
+ * ID_PATH_ATA_COMPAT
+ */
+ if (compat_path)
+ udev_builtin_add_property(dev, test, "ID_PATH_ATA_COMPAT", compat_path);
+
return 0;
}
case TK_M_IMPORT_CMDLINE: {
_cleanup_free_ char *value = NULL;
- r = proc_cmdline_get_key(token->value, PROC_CMDLINE_VALUE_OPTIONAL, &value);
+ r = proc_cmdline_get_key(token->value, PROC_CMDLINE_VALUE_OPTIONAL|PROC_CMDLINE_IGNORE_EFI_OPTIONS, &value);
if (r < 0)
return log_rule_error_errno(dev, rules, r,
"Failed to read '%s' option from /proc/cmdline: %m",
set -e
TEST_DESCRIPTION="Job-related tests"
TEST_NO_QEMU=1
+IMAGE_NAME="default"
. $TEST_BASE_DIR/test-functions
#!/usr/bin/env bash
set -e
TEST_DESCRIPTION="systemd-nspawn smoke test"
-IMAGE_NAME=nspawn
+IMAGE_NAME="nspawn"
TEST_NO_NSPAWN=1
. $TEST_BASE_DIR/test-functions
#!/usr/bin/env bash
set -e
TEST_DESCRIPTION="/etc/machine-id testing"
-IMAGE_NAME=badid
+IMAGE_NAME="badid"
TEST_NO_NSPAWN=1
. $TEST_BASE_DIR/test-functions
#!/usr/bin/env bash
set -e
TEST_DESCRIPTION="Sysuser-related tests"
-IMAGE_NAME=sysusers
+IMAGE_NAME="sysusers"
. $TEST_BASE_DIR/test-functions
test_setup() {
--- /dev/null
+[DHCPv4]
+SendOption=1:string:
+SendOption=1:uint8:
+SendOption=1:uint16:
+SendOption=1:uint32:
+SendOption=1:ipv4address:
+SendOption=1:ipv4address:127.0.0.1
+SendOption=1:ipv6address:
+SendOption=1:ipv6address:52:54:00:b9:b5:61
RestrictRealtime=
RestrictSUIDSGID=
RuntimeDirectory=
+RuntimeDirectoryInodesMax=
RuntimeDirectoryMode=
RuntimeDirectoryPreserve=
RuntimeDirectorySize=
project_source_root,
'@OUTPUT@',
'fuzzers',
- '-Db_lundef=false -Db_sanitize=address,undefined',
+ '-Db_lundef=false -Db_sanitize=address,undefined ' +
+ '--optimization=@0@'.format(get_option('optimization')),
' '.join(cc.cmd_array()),
cxx_cmd])
QEMU_MEM="${QEMU_MEM:-512M}"
IMAGE_NAME=${IMAGE_NAME:-default}
TEST_REQUIRE_INSTALL_TESTS="${TEST_REQUIRE_INSTALL_TESTS:-1}"
+TEST_PARALLELIZE="${TEST_PARALLELIZE:-0}"
LOOPDEV=
# Decide if we can (and want to) run QEMU with KVM acceleration.
$KERNEL_APPEND \
"
+ [ -e "$IMAGE_PRIVATE" ] && image="$IMAGE_PRIVATE" || image="$IMAGE_PUBLIC"
QEMU_OPTIONS="-smp $QEMU_SMP \
-net none \
-m $QEMU_MEM \
-nographic \
-kernel $KERNEL_BIN \
--drive format=raw,cache=unsafe,file=${IMAGESTATEDIR}/${IMAGE_NAME}.img \
+-drive format=raw,cache=unsafe,file=$image \
$QEMU_OPTIONS \
"
_size=$((4*_size))
fi
- image="${TESTDIR}/${IMAGE_NAME}.img"
- public="$IMAGESTATEDIR/${IMAGE_NAME}.img"
- echo "Setting up $public (${_size} MB)"
- rm -f "$image" "$public"
+ echo "Setting up $IMAGE_PUBLIC (${_size} MB)"
+ rm -f "$IMAGE_PRIVATE" "$IMAGE_PUBLIC"
# Create the blank file to use as a root filesystem
- truncate -s "${_size}M" "$image"
- ln -vs "$(realpath $image)" "$public"
+ truncate -s "${_size}M" "$IMAGE_PRIVATE"
+ ln -vs "$(realpath $IMAGE_PRIVATE)" "$IMAGE_PUBLIC"
- LOOPDEV=$(losetup --show -P -f "$public")
+ LOOPDEV=$(losetup --show -P -f "$IMAGE_PUBLIC")
[ -b "$LOOPDEV" ] || return 1
sfdisk "$LOOPDEV" <<EOF
,$((_size-50))M
mount_initdir() {
if [ -z "${LOOPDEV}" ]; then
- image="${IMAGESTATEDIR}/${IMAGE_NAME}.img"
+ [ -e "$IMAGE_PRIVATE" ] && image="$IMAGE_PRIVATE" || image="$IMAGE_PUBLIC"
LOOPDEV=$(losetup --show -P -f "$image")
[ -b "$LOOPDEV" ] || return 1
umount_loopback() {
# unmount the loopback device from all places. Otherwise we risk file
# system corruption.
- image="${IMAGESTATEDIR}/${IMAGE_NAME}.img"
- for device in $(losetup -l | awk '$6=="'"$image"'" {print $1}'); do
+ for device in $(losetup -l | awk '$6=="'"$IMAGE_PUBLIC"'" {print $1}'); do
ddebug "Unmounting all uses of $device"
mount | awk '/^'"${device}"'p/{print $1}' | xargs --no-run-if-empty umount -v
done
EOF
export TESTDIR
fi
+
+ IMAGE_PRIVATE="${TESTDIR}/${IMAGE_NAME}.img"
+ IMAGE_PUBLIC="${IMAGESTATEDIR}/${IMAGE_NAME}.img"
}
import_initdir() {
(
set +e
_umount_dir $initdir
- rm -vf "${IMAGESTATEDIR}/${IMAGE_NAME}.img"
+ rm -vf "$IMAGE_PUBLIC"
rm -vfr "$TESTDIR"
rm -vf "$STATEFILE"
) || :
exit 1
fi
- image="${TESTDIR}/${IMAGE_NAME}.img"
- public="${IMAGESTATEDIR}/${IMAGE_NAME}.img"
- if [ -e "$image" ]; then
- echo "Reusing existing image $PWD/$image → $(realpath $image)"
+ if [ -e "$IMAGE_PRIVATE" ]; then
+ echo "Reusing existing image $IMAGE_PRIVATE → $(realpath $IMAGE_PRIVATE)"
mount_initdir
- elif [ -e "$public" ]; then
- echo "Reusing existing cached image $PWD/$public → $(realpath $public)"
- ln -s "$(realpath $public)" "$image"
+ elif [ -e "$IMAGE_PUBLIC" ]; then
+ echo "Reusing existing cached image $IMAGE_PUBLIC → $(realpath $IMAGE_PUBLIC)"
+ if [ ${TEST_PARALLELIZE} -ne 0 ]; then
+ cp -v "$(realpath $IMAGE_PUBLIC)" "$IMAGE_PRIVATE"
+ else
+ ln -sv "$(realpath $IMAGE_PUBLIC)" "$IMAGE_PRIVATE"
+ fi
mount_initdir
else
test_create_image
rm -rf $build
mkdir -p $build
-fuzzflag="oss-fuzz=true"
if [ -z "$FUZZING_ENGINE" ]; then
fuzzflag="llvm-fuzz=true"
+else
+ fuzzflag="oss-fuzz=true"
+ if [[ "$SANITIZER" == undefined ]]; then
+ UBSAN_FLAGS="-fsanitize=pointer-overflow -fno-sanitize-recover=pointer-overflow"
+ CFLAGS="$CFLAGS $UBSAN_FLAGS"
+ CXXFLAGS="$CXXFLAGS $UBSAN_FLAGS"
+ fi
fi
meson $build -D$fuzzflag -Db_lundef=false
RUN_ASAN|RUN_CLANG_ASAN)
if [[ "$phase" = "RUN_CLANG_ASAN" ]]; then
ENV_VARS="-e CC=clang -e CXX=clang++"
- MESON_ARGS="-Db_lundef=false" # See https://github.com/mesonbuild/meson/issues/764
+ # Build fuzzer regression tests only with clang (for now),
+ # see: https://github.com/systemd/systemd/pull/15886#issuecomment-632689604
+ # -Db_lundef=false: See https://github.com/mesonbuild/meson/issues/764
+ MESON_ARGS="-Db_lundef=false -Dfuzz-tests=true --optimization=1"
fi
docker exec $ENV_VARS -it $CONT_NAME meson --werror -Dtests=unsafe -Db_sanitize=address,undefined -Dsplit-usr=true $MESON_ARGS build
$DOCKER_EXEC ninja -v -C build