From a2b32ed976898188bc98d9b6c7eec3dc45f4abf0 Mon Sep 17 00:00:00 2001
From: Antonio Alvarez Feijoo <antonio.feijoo@suse.com>
Date: Wed, 1 Mar 2023 11:21:16 +0100
Subject: [PATCH 1/3] fix(dracut-systemd): do not hardcode the systemd
 generator directory

The normal directory is the first argument passed to the systemd generator,
so use it instead of hardcoding /run/systemd/generator.
---
 modules.d/98dracut-systemd/rootfs-generator.sh | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/modules.d/98dracut-systemd/rootfs-generator.sh b/modules.d/98dracut-systemd/rootfs-generator.sh
index b98e4e577..32179fb40 100755
--- a/modules.d/98dracut-systemd/rootfs-generator.sh
+++ b/modules.d/98dracut-systemd/rootfs-generator.sh
@@ -17,7 +17,7 @@ generator_wait_for_dev() {
         # after remote-fs-pre.target since the initqueue is ordered before it so
         # it will never actually show up (think Tang-pinned rootfs).
         cat > "$hookdir/initqueue/finished/devexists-${_name}.sh" << EOF
-if ! grep -q After=remote-fs-pre.target /run/systemd/generator/systemd-cryptsetup@*.service 2>/dev/null; then
+if ! grep -q After=remote-fs-pre.target "$GENERATOR_DIR"/systemd-cryptsetup@*.service 2>/dev/null; then
     [ -e "$1" ]
 fi
 EOF
@@ -77,12 +77,12 @@ generator_fsck_after_pre_mount() {
     [ -z "$1" ] && return 0
 
     _name=$(dev_unit_name "$1")
-    [ -d /run/systemd/generator/systemd-fsck@"${_name}".service.d ] || mkdir -p /run/systemd/generator/systemd-fsck@"${_name}".service.d
-    if ! [ -f /run/systemd/generator/systemd-fsck@"${_name}".service.d/after-pre-mount.conf ]; then
+    [ -d "$GENERATOR_DIR"/systemd-fsck@"${_name}".service.d ] || mkdir -p "$GENERATOR_DIR"/systemd-fsck@"${_name}".service.d
+    if ! [ -f "$GENERATOR_DIR"/systemd-fsck@"${_name}".service.d/after-pre-mount.conf ]; then
         {
             echo "[Unit]"
             echo "After=dracut-pre-mount.service"
-        } > /run/systemd/generator/systemd-fsck@"${_name}".service.d/after-pre-mount.conf
+        } > "$GENERATOR_DIR"/systemd-fsck@"${_name}".service.d/after-pre-mount.conf
     fi
 
 }

From e21f8f7d5abaae37ada8c7a6dc91c2d878e0b501 Mon Sep 17 00:00:00 2001
From: Antonio Alvarez Feijoo <antonio.feijoo@suse.com>
Date: Wed, 1 Mar 2023 12:07:29 +0100
Subject: [PATCH 2/3] fix(dracut-systemd): check and create generator dir
 outside of inner function

---
 modules.d/98dracut-systemd/rootfs-generator.sh | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/modules.d/98dracut-systemd/rootfs-generator.sh b/modules.d/98dracut-systemd/rootfs-generator.sh
index 32179fb40..0ba1709ba 100755
--- a/modules.d/98dracut-systemd/rootfs-generator.sh
+++ b/modules.d/98dracut-systemd/rootfs-generator.sh
@@ -51,7 +51,6 @@ generator_mount_rootfs() {
     [ -z "$1" ] && return 0
 
     _name=$(dev_unit_name "$1")
-    [ -d "$GENERATOR_DIR" ] || mkdir -p "$GENERATOR_DIR"
     if ! [ -f "$GENERATOR_DIR"/sysroot.mount ]; then
         {
             echo "[Unit]"
@@ -101,9 +100,11 @@ case "${root#block:}" in
         ;;
 esac
 
-GENERATOR_DIR="$1"
-
 if [ "$rootok" = "1" ]; then
+    GENERATOR_DIR="$1"
+    [ -z "$GENERATOR_DIR" ] && exit 1
+    [ -d "$GENERATOR_DIR" ] || mkdir -p "$GENERATOR_DIR"
+
     generator_wait_for_dev "${root#block:}" "$RDRETRY"
     generator_fsck_after_pre_mount "${root#block:}"
     strstr "$(cat /proc/cmdline)" 'root=' || generator_mount_rootfs "${root#block:}" "$(getarg rootfstype=)" "$(getarg rootflags=)"

From 9d37c2794339a1fac89d87b3acfd81b9397e26e3 Mon Sep 17 00:00:00 2001
From: Antonio Alvarez Feijoo <antonio.feijoo@suse.com>
Date: Wed, 8 Mar 2023 08:25:38 +0100
Subject: [PATCH 3/3] fix(dracut-systemd): rootfs-generator cannot write
 outside of generator dir

Although it was already documented in systemd.generator(7) that generators must
not write to locations other than those passed as arguments, since
https://github.com/systemd/systemd/commit/ca6ce62d systemd executes generators
in a mount namespace "sandbox", so now the hooks created by the rootfs-generator
are lost.

These hooks are created using the root= cmdline argument, so this patch moves
the creation of these hooks to a cmdline hook.

Fixes issue #2211
Fixes issue #2225
---
 modules.d/98dracut-systemd/module-setup.sh    |  2 +
 modules.d/98dracut-systemd/parse-root.sh      | 38 +++++++++++++++++++
 .../98dracut-systemd/rootfs-generator.sh      | 20 +---------
 3 files changed, 41 insertions(+), 19 deletions(-)
 create mode 100755 modules.d/98dracut-systemd/parse-root.sh

diff --git a/modules.d/98dracut-systemd/module-setup.sh b/modules.d/98dracut-systemd/module-setup.sh
index b7da86dba..31953773d 100755
--- a/modules.d/98dracut-systemd/module-setup.sh
+++ b/modules.d/98dracut-systemd/module-setup.sh
@@ -37,6 +37,8 @@ install() {
 
     inst_script "$moddir/rootfs-generator.sh" "$systemdutildir"/system-generators/dracut-rootfs-generator
 
+    inst_hook cmdline 00 "$moddir/parse-root.sh"
+
     for i in \
         dracut-cmdline.service \
         dracut-cmdline-ask.service \
diff --git a/modules.d/98dracut-systemd/parse-root.sh b/modules.d/98dracut-systemd/parse-root.sh
new file mode 100755
index 000000000..90f145afa
--- /dev/null
+++ b/modules.d/98dracut-systemd/parse-root.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+type getarg > /dev/null 2>&1 || . /lib/dracut-lib.sh
+
+root=$(getarg root=)
+case "${root#block:}" in
+    LABEL=* | UUID=* | PARTUUID=* | PARTLABEL=*)
+        root="block:$(label_uuid_to_dev "$root")"
+        rootok=1
+        ;;
+    /dev/nfs | /dev/root) # ignore legacy
+        ;;
+    /dev/*)
+        root="block:${root}"
+        rootok=1
+        ;;
+esac
+
+if [ "$rootok" = "1" ]; then
+    root_dev="${root#block:}"
+    root_name="$(str_replace "$root_dev" '/' '\x2f')"
+    if ! [ -e "$hookdir/initqueue/finished/devexists-${root_name}.sh" ]; then
+
+        # If a LUKS device needs unlocking via systemd in the initrd, assume
+        # it's for the root device. In that case, don't block on it if it's
+        # after remote-fs-pre.target since the initqueue is ordered before it so
+        # it will never actually show up (think Tang-pinned rootfs).
+        cat > "$hookdir/initqueue/finished/devexists-${root_name}.sh" << EOF
+if ! grep -q After=remote-fs-pre.target /run/systemd/generator/systemd-cryptsetup@*.service 2>/dev/null; then
+    [ -e "$root_dev" ]
+fi
+EOF
+        {
+            printf '[ -e "%s" ] || ' "$root_dev"
+            printf 'warn "\"%s\" does not exist"\n' "$root_dev"
+        } >> "$hookdir/emergency/80-${root_name}.sh"
+    fi
+fi
diff --git a/modules.d/98dracut-systemd/rootfs-generator.sh b/modules.d/98dracut-systemd/rootfs-generator.sh
index 0ba1709ba..cef3f4905 100755
--- a/modules.d/98dracut-systemd/rootfs-generator.sh
+++ b/modules.d/98dracut-systemd/rootfs-generator.sh
@@ -6,28 +6,10 @@ generator_wait_for_dev() {
     local _name
     local _timeout
 
-    _name="$(str_replace "$1" '/' '\x2f')"
+    _name=$(dev_unit_name "$1")
     _timeout=$(getarg rd.timeout)
     _timeout=${_timeout:-0}
 
-    if ! [ -e "$hookdir/initqueue/finished/devexists-${_name}.sh" ]; then
-
-        # If a LUKS device needs unlocking via systemd in the initrd, assume
-        # it's for the root device. In that case, don't block on it if it's
-        # after remote-fs-pre.target since the initqueue is ordered before it so
-        # it will never actually show up (think Tang-pinned rootfs).
-        cat > "$hookdir/initqueue/finished/devexists-${_name}.sh" << EOF
-if ! grep -q After=remote-fs-pre.target "$GENERATOR_DIR"/systemd-cryptsetup@*.service 2>/dev/null; then
-    [ -e "$1" ]
-fi
-EOF
-        {
-            printf '[ -e "%s" ] || ' "$1"
-            printf 'warn "\"%s\" does not exist"\n' "$1"
-        } >> "$hookdir/emergency/80-${_name}.sh"
-    fi
-
-    _name=$(dev_unit_name "$1")
     if ! [ -L "$GENERATOR_DIR"/initrd.target.wants/"${_name}".device ]; then
         [ -d "$GENERATOR_DIR"/initrd.target.wants ] || mkdir -p "$GENERATOR_DIR"/initrd.target.wants
         ln -s ../"${_name}".device "$GENERATOR_DIR"/initrd.target.wants/"${_name}".device