Skip to content

Commit 1758ec7

Browse files
authored
Merge pull request #16 from GlitchSlayed/codex/implement-cmdline-validation-in-uki-setup.sh
Add cmdline validation and Fedora-version-aware metadata caching
2 parents 70f6e11 + 6386308 commit 1758ec7

1 file changed

Lines changed: 252 additions & 11 deletions

File tree

‎uki-setup.sh‎

Lines changed: 252 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ INITRAMFS_REQUIRED_LIST="/etc/uki/initramfs-required.txt"
6060
INITRAMFS_FORBIDDEN_LIST="/etc/uki/initramfs-forbidden.txt"
6161
INITRAMFS_STATE_DIR="/var/lib/uki-build"
6262
INITRAMFS_STRICT_DIFF=0
63+
CMDLINE_MIN_TOKENS=3
6364

6465
# =============================================================================
6566
# ── SCRIPT INTERNALS ───────────────────────────────────────────────────────
@@ -85,6 +86,83 @@ sanitize_cmdline() {
8586
sed -E 's/(^| )BOOT_IMAGE=[^ ]*//g; s/(^| )initrd=[^ ]*//g; s/(^| )rd\.driver\.blacklist=[^ ]*//g; s/ +/ /g; s/^ //; s/ $//'
8687
}
8788

89+
count_cmdline_tokens() {
90+
local cmdline="$1"
91+
awk '{print NF}' <<<"$cmdline"
92+
}
93+
94+
extract_root_uuid() {
95+
local cmdline="$1" token
96+
for token in $cmdline; do
97+
if [[ "$token" =~ ^root=UUID=([^[:space:]]+)$ ]]; then
98+
echo "${BASH_REMATCH[1]}"
99+
return 0
100+
fi
101+
done
102+
return 1
103+
}
104+
105+
major_version() {
106+
local version="$1"
107+
echo "${version%%.*}"
108+
}
109+
110+
get_os_version_id() {
111+
local version_id=""
112+
if [[ -r /etc/os-release ]]; then
113+
version_id=$(awk -F= '$1=="VERSION_ID" {gsub(/"/,"",$2); print $2}' /etc/os-release)
114+
fi
115+
echo "$version_id"
116+
}
117+
118+
validate_root_uuid_against_blkid() {
119+
local cmdline="$1" source="$2" detected="$3" uuid
120+
121+
if ! uuid=$(extract_root_uuid "$cmdline"); then
122+
return 0
123+
fi
124+
125+
if [[ "$uuid" == "REPLACE-ME" ]]; then
126+
die "Refusing to continue: cmdline from ${source} still contains root=UUID=REPLACE-ME."
127+
fi
128+
129+
if ! blkid -t "UUID=$uuid" >/dev/null 2>&1; then
130+
if [[ "$detected" == "1" ]]; then
131+
die "Detected cmdline from ${source} references root UUID '${uuid}', but blkid cannot find it."
132+
fi
133+
die "Configured cmdline references root UUID '${uuid}', but blkid cannot find it."
134+
fi
135+
}
136+
137+
warn_if_cmdline_short() {
138+
local cmdline="$1" source="$2" token_count
139+
token_count=$(count_cmdline_tokens "$cmdline")
140+
if (( token_count < CMDLINE_MIN_TOKENS )); then
141+
warn "Cmdline from ${source} looks unusually short after sanitization (${token_count} token(s)): ${cmdline}"
142+
fi
143+
}
144+
145+
persist_cmdline_metadata() {
146+
local cmdline="$1" source="$2" version_id="$3"
147+
local metadata_dir="${INITRAMFS_STATE_DIR}/cmdline"
148+
149+
mkdir -p "$metadata_dir"
150+
printf '%s\n' "$cmdline" > "${metadata_dir}/effective-cmdline"
151+
printf '%s\n' "$source" > "${metadata_dir}/source"
152+
printf '%s\n' "$version_id" > "${metadata_dir}/version-id"
153+
date -u +%Y-%m-%dT%H:%M:%SZ > "${metadata_dir}/updated-at"
154+
}
155+
156+
validate_final_cmdline() {
157+
local cmdline="$1" source="$2" detected="$3"
158+
159+
[[ "$cmdline" =~ (^|[[:space:]])root=UUID=REPLACE-ME($|[[:space:]]) ]] \
160+
&& die "Refusing to build UKI with placeholder cmdline token root=UUID=REPLACE-ME."
161+
162+
warn_if_cmdline_short "$cmdline" "$source"
163+
validate_root_uuid_against_blkid "$cmdline" "$source" "$detected"
164+
}
165+
88166
read_grub_cmdline() {
89167
local file line value
90168

@@ -104,13 +182,49 @@ read_grub_cmdline() {
104182
}
105183

106184
get_effective_cmdline() {
107-
local proc_cmdline kernel_cmdline grub_cmdline
185+
local proc_cmdline kernel_cmdline grub_cmdline cached_cmdline
186+
local cmdline_source="configured CMDLINE" detected_cmdline=0
187+
local metadata_dir="${INITRAMFS_STATE_DIR}/cmdline"
188+
local current_version_id cached_version_id current_major cached_major
189+
190+
current_version_id=$(get_os_version_id)
191+
current_major=$(major_version "$current_version_id")
192+
193+
if [[ -r "${metadata_dir}/version-id" ]]; then
194+
cached_version_id=$(<"${metadata_dir}/version-id")
195+
cached_major=$(major_version "$cached_version_id")
196+
if [[ -n "$cached_major" && -n "$current_major" && "$cached_major" != "$current_major" ]]; then
197+
warn "Fedora major VERSION_ID changed (${cached_version_id} -> ${current_version_id}); forcing fresh cmdline detection."
198+
cached_cmdline=""
199+
elif [[ -r "${metadata_dir}/effective-cmdline" ]]; then
200+
cached_cmdline=$(<"${metadata_dir}/effective-cmdline")
201+
fi
202+
elif [[ -r "${metadata_dir}/effective-cmdline" ]]; then
203+
cached_cmdline=$(<"${metadata_dir}/effective-cmdline")
204+
fi
108205

109206
if [[ "$AUTO_DETECT_CMDLINE" -eq 1 ]]; then
207+
if [[ -n "${cached_cmdline:-}" ]]; then
208+
cached_cmdline=$(printf '%s\n' "$cached_cmdline" | sanitize_cmdline | xargs || true)
209+
if [[ -n "$cached_cmdline" ]]; then
210+
info "Using cached cmdline metadata from ${metadata_dir}/effective-cmdline"
211+
cmdline_source="cached metadata"
212+
detected_cmdline=1
213+
validate_final_cmdline "$cached_cmdline" "$cmdline_source" "$detected_cmdline"
214+
persist_cmdline_metadata "$cached_cmdline" "$cmdline_source" "$current_version_id"
215+
echo "$cached_cmdline"
216+
return 0
217+
fi
218+
fi
219+
110220
if [[ -r /proc/cmdline ]]; then
111221
proc_cmdline=$(sanitize_cmdline < /proc/cmdline | xargs || true)
112222
if [[ -n "$proc_cmdline" && "$proc_cmdline" =~ (root=|rd.luks.uuid=|rootfstype=) ]]; then
113223
info "Using cmdline from /proc/cmdline"
224+
cmdline_source="/proc/cmdline"
225+
detected_cmdline=1
226+
validate_final_cmdline "$proc_cmdline" "$cmdline_source" "$detected_cmdline"
227+
persist_cmdline_metadata "$proc_cmdline" "$cmdline_source" "$current_version_id"
114228
echo "$proc_cmdline"
115229
return 0
116230
fi
@@ -120,6 +234,10 @@ get_effective_cmdline() {
120234
kernel_cmdline=$(sanitize_cmdline < /etc/kernel/cmdline | xargs || true)
121235
if [[ -n "$kernel_cmdline" && "$kernel_cmdline" =~ (root=|rd.luks.uuid=|rootfstype=) ]]; then
122236
info "Using cmdline from /etc/kernel/cmdline"
237+
cmdline_source="/etc/kernel/cmdline"
238+
detected_cmdline=1
239+
validate_final_cmdline "$kernel_cmdline" "$cmdline_source" "$detected_cmdline"
240+
persist_cmdline_metadata "$kernel_cmdline" "$cmdline_source" "$current_version_id"
123241
echo "$kernel_cmdline"
124242
return 0
125243
fi
@@ -130,6 +248,10 @@ get_effective_cmdline() {
130248
grub_cmdline=$(printf '%s\n' "$grub_cmdline" | sanitize_cmdline | xargs || true)
131249
if [[ -n "$grub_cmdline" && "$grub_cmdline" =~ (root=|rd.luks.uuid=|rootfstype=) ]]; then
132250
info "Using cmdline from GRUB configuration"
251+
cmdline_source="GRUB configuration"
252+
detected_cmdline=1
253+
validate_final_cmdline "$grub_cmdline" "$cmdline_source" "$detected_cmdline"
254+
persist_cmdline_metadata "$grub_cmdline" "$cmdline_source" "$current_version_id"
133255
echo "$grub_cmdline"
134256
return 0
135257
fi
@@ -138,6 +260,9 @@ get_effective_cmdline() {
138260
warn "Auto-detect enabled, but no bootable cmdline was detected. Falling back to configured CMDLINE."
139261
fi
140262

263+
validate_final_cmdline "$CMDLINE" "$cmdline_source" "$detected_cmdline"
264+
persist_cmdline_metadata "$CMDLINE" "$cmdline_source" "$current_version_id"
265+
141266
echo "$CMDLINE"
142267
}
143268

@@ -460,6 +585,7 @@ INITRAMFS_REQUIRED_LIST="__INITRAMFS_REQUIRED_LIST__"
460585
INITRAMFS_FORBIDDEN_LIST="__INITRAMFS_FORBIDDEN_LIST__"
461586
INITRAMFS_STATE_DIR="__INITRAMFS_STATE_DIR__"
462587
INITRAMFS_STRICT_DIFF=__INITRAMFS_STRICT_DIFF__
588+
CMDLINE_MIN_TOKENS=__CMDLINE_MIN_TOKENS__
463589
# ─────────────────────────────────────────────────────────────────────────────
464590
465591
RED='\e[31;1m'; GRN='\e[32;1m'; YLW='\e[33;1m'; RST='\e[0m'
@@ -600,6 +726,83 @@ sanitize_cmdline() {
600726
sed -E 's/(^| )BOOT_IMAGE=[^ ]*//g; s/(^| )initrd=[^ ]*//g; s/(^| )rd\.driver\.blacklist=[^ ]*//g; s/ +/ /g; s/^ //; s/ $//'
601727
}
602728
729+
count_cmdline_tokens() {
730+
local cmdline="$1"
731+
awk '{print NF}' <<<"$cmdline"
732+
}
733+
734+
extract_root_uuid() {
735+
local cmdline="$1" token
736+
for token in $cmdline; do
737+
if [[ "$token" =~ ^root=UUID=([^[:space:]]+)$ ]]; then
738+
echo "${BASH_REMATCH[1]}"
739+
return 0
740+
fi
741+
done
742+
return 1
743+
}
744+
745+
major_version() {
746+
local version="$1"
747+
echo "${version%%.*}"
748+
}
749+
750+
get_os_version_id() {
751+
local version_id=""
752+
if [[ -r /etc/os-release ]]; then
753+
version_id=$(awk -F= '$1=="VERSION_ID" {gsub(/"/,"",$2); print $2}' /etc/os-release)
754+
fi
755+
echo "$version_id"
756+
}
757+
758+
validate_root_uuid_against_blkid() {
759+
local cmdline="$1" source="$2" detected="$3" uuid
760+
761+
if ! uuid=$(extract_root_uuid "$cmdline"); then
762+
return 0
763+
fi
764+
765+
if [[ "$uuid" == "REPLACE-ME" ]]; then
766+
die "Refusing to continue: cmdline from ${source} still contains root=UUID=REPLACE-ME."
767+
fi
768+
769+
if ! blkid -t "UUID=$uuid" >/dev/null 2>&1; then
770+
if [[ "$detected" == "1" ]]; then
771+
die "Detected cmdline from ${source} references root UUID '${uuid}', but blkid cannot find it."
772+
fi
773+
die "Configured cmdline references root UUID '${uuid}', but blkid cannot find it."
774+
fi
775+
}
776+
777+
warn_if_cmdline_short() {
778+
local cmdline="$1" source="$2" token_count
779+
token_count=$(count_cmdline_tokens "$cmdline")
780+
if (( token_count < CMDLINE_MIN_TOKENS )); then
781+
warn "Cmdline from ${source} looks unusually short after sanitization (${token_count} token(s)): ${cmdline}"
782+
fi
783+
}
784+
785+
persist_cmdline_metadata() {
786+
local cmdline="$1" source="$2" version_id="$3"
787+
local metadata_dir="${INITRAMFS_STATE_DIR}/cmdline"
788+
789+
mkdir -p "$metadata_dir"
790+
printf '%s\n' "$cmdline" > "${metadata_dir}/effective-cmdline"
791+
printf '%s\n' "$source" > "${metadata_dir}/source"
792+
printf '%s\n' "$version_id" > "${metadata_dir}/version-id"
793+
date -u +%Y-%m-%dT%H:%M:%SZ > "${metadata_dir}/updated-at"
794+
}
795+
796+
validate_final_cmdline() {
797+
local cmdline="$1" source="$2" detected="$3"
798+
799+
[[ "$cmdline" =~ (^|[[:space:]])root=UUID=REPLACE-ME($|[[:space:]]) ]] \
800+
&& die "Refusing to build UKI with placeholder cmdline token root=UUID=REPLACE-ME."
801+
802+
warn_if_cmdline_short "$cmdline" "$source"
803+
validate_root_uuid_against_blkid "$cmdline" "$source" "$detected"
804+
}
805+
603806
read_grub_cmdline() {
604807
local file line value
605808
@@ -619,13 +822,49 @@ read_grub_cmdline() {
619822
}
620823
621824
get_effective_cmdline() {
622-
local proc_cmdline kernel_cmdline grub_cmdline
825+
local proc_cmdline kernel_cmdline grub_cmdline cached_cmdline
826+
local cmdline_source="configured CMDLINE" detected_cmdline=0
827+
local metadata_dir="${INITRAMFS_STATE_DIR}/cmdline"
828+
local current_version_id cached_version_id current_major cached_major
829+
830+
current_version_id=$(get_os_version_id)
831+
current_major=$(major_version "$current_version_id")
623832
624833
if [[ "$AUTO_DETECT_CMDLINE" -eq 1 ]]; then
834+
if [[ -r "${metadata_dir}/version-id" ]]; then
835+
cached_version_id=$(<"${metadata_dir}/version-id")
836+
cached_major=$(major_version "$cached_version_id")
837+
if [[ -n "$cached_major" && -n "$current_major" && "$cached_major" != "$current_major" ]]; then
838+
warn "Fedora major VERSION_ID changed (${cached_version_id} -> ${current_version_id}); forcing fresh cmdline detection."
839+
cached_cmdline=""
840+
elif [[ -r "${metadata_dir}/effective-cmdline" ]]; then
841+
cached_cmdline=$(<"${metadata_dir}/effective-cmdline")
842+
fi
843+
elif [[ -r "${metadata_dir}/effective-cmdline" ]]; then
844+
cached_cmdline=$(<"${metadata_dir}/effective-cmdline")
845+
fi
846+
847+
if [[ -n "${cached_cmdline:-}" ]]; then
848+
cached_cmdline=$(printf '%s\n' "$cached_cmdline" | sanitize_cmdline | xargs || true)
849+
if [[ -n "$cached_cmdline" ]]; then
850+
info "Using cached cmdline metadata from ${metadata_dir}/effective-cmdline"
851+
cmdline_source="cached metadata"
852+
detected_cmdline=1
853+
validate_final_cmdline "$cached_cmdline" "$cmdline_source" "$detected_cmdline"
854+
persist_cmdline_metadata "$cached_cmdline" "$cmdline_source" "$current_version_id"
855+
echo "$cached_cmdline"
856+
return 0
857+
fi
858+
fi
859+
625860
if [[ -r /proc/cmdline ]]; then
626861
proc_cmdline=$(sanitize_cmdline < /proc/cmdline | xargs || true)
627862
if [[ -n "$proc_cmdline" && "$proc_cmdline" =~ (root=|rd.luks.uuid=|rootfstype=) ]]; then
628863
info "Using cmdline from /proc/cmdline: ${proc_cmdline}"
864+
cmdline_source="/proc/cmdline"
865+
detected_cmdline=1
866+
validate_final_cmdline "$proc_cmdline" "$cmdline_source" "$detected_cmdline"
867+
persist_cmdline_metadata "$proc_cmdline" "$cmdline_source" "$current_version_id"
629868
echo "$proc_cmdline"
630869
return 0
631870
fi
@@ -635,6 +874,10 @@ get_effective_cmdline() {
635874
kernel_cmdline=$(sanitize_cmdline < /etc/kernel/cmdline | xargs || true)
636875
if [[ -n "$kernel_cmdline" && "$kernel_cmdline" =~ (root=|rd.luks.uuid=|rootfstype=) ]]; then
637876
info "Using cmdline from /etc/kernel/cmdline: ${kernel_cmdline}"
877+
cmdline_source="/etc/kernel/cmdline"
878+
detected_cmdline=1
879+
validate_final_cmdline "$kernel_cmdline" "$cmdline_source" "$detected_cmdline"
880+
persist_cmdline_metadata "$kernel_cmdline" "$cmdline_source" "$current_version_id"
638881
echo "$kernel_cmdline"
639882
return 0
640883
fi
@@ -645,6 +888,10 @@ get_effective_cmdline() {
645888
grub_cmdline=$(printf '%s\n' "$grub_cmdline" | sanitize_cmdline | xargs || true)
646889
if [[ -n "$grub_cmdline" && "$grub_cmdline" =~ (root=|rd.luks.uuid=|rootfstype=) ]]; then
647890
info "Using cmdline from GRUB configuration: ${grub_cmdline}"
891+
cmdline_source="GRUB configuration"
892+
detected_cmdline=1
893+
validate_final_cmdline "$grub_cmdline" "$cmdline_source" "$detected_cmdline"
894+
persist_cmdline_metadata "$grub_cmdline" "$cmdline_source" "$current_version_id"
648895
echo "$grub_cmdline"
649896
return 0
650897
fi
@@ -653,6 +900,8 @@ get_effective_cmdline() {
653900
warn "Auto-detect enabled, but no bootable cmdline was detected. Falling back to configured CMDLINE: ${CMDLINE}"
654901
fi
655902
903+
validate_final_cmdline "$CMDLINE" "$cmdline_source" "$detected_cmdline"
904+
persist_cmdline_metadata "$CMDLINE" "$cmdline_source" "$current_version_id"
656905
info "Using configured cmdline: ${CMDLINE}"
657906
echo "$CMDLINE"
658907
}
@@ -845,6 +1094,7 @@ BUILDBODY
8451094
-e "s|__INITRAMFS_FORBIDDEN_LIST__|${INITRAMFS_FORBIDDEN_LIST}|g" \
8461095
-e "s|__INITRAMFS_STATE_DIR__|${INITRAMFS_STATE_DIR}|g" \
8471096
-e "s|__INITRAMFS_STRICT_DIFF__|${INITRAMFS_STRICT_DIFF}|g" \
1097+
-e "s|__CMDLINE_MIN_TOKENS__|${CMDLINE_MIN_TOKENS}|g" \
8481098
"$BUILD_SCRIPT"
8491099

8501100
chmod 0755 "$BUILD_SCRIPT"
@@ -954,15 +1204,6 @@ phase_initial_build() {
9541204
hr
9551205
info "Phase 6: Building UKI for current kernel: $(uname -r)"
9561206

957-
if [[ "$AUTO_DETECT_CMDLINE" -eq 0 && "$CMDLINE" == "root=UUID=REPLACE-ME rw quiet rhgb" ]]; then
958-
warn "────────────────────────────────────────────────────────────"
959-
warn "AUTO_DETECT_CMDLINE is disabled and CMDLINE is still placeholder text."
960-
warn "Set CMDLINE to a real root=... value, or enable AUTO_DETECT_CMDLINE=1."
961-
warn "────────────────────────────────────────────────────────────"
962-
read -r -p "Continue with placeholder CMDLINE anyway? [y/N] " ans
963-
[[ "${ans,,}" == "y" ]] || { info "Aborted. Set CMDLINE and re-run."; exit 0; }
964-
fi
965-
9661207
"$BUILD_SCRIPT" "$(uname -r)"
9671208
}
9681209

0 commit comments

Comments
 (0)