Skip to content

Commit 7e967be

Browse files
committed
initrd/functions, init: harden rollback marker path handling
Prevent path traversal via a tampered rollback marker file: - Read only the first line of the marker (blocks multi-line injection) - Resolve the path with readlink -f before using it - Validate the resolved path matches /boot/<brand>/backup_*.rom pattern; clear the marker and continue boot if it does not - Use the resolved, validated path for the actual reflash Also correct the comment in init for the manual rollback path ('b'): the fallback-to-most-recent-backup behaviour described in the old comment was never implemented; check_pending_rollback() returns silently when no marker is present, so boot just continues. Signed-off-by: Thierry Laurion <insurgo@riseup.net>
1 parent ac36ee6 commit 7e967be

2 files changed

Lines changed: 25 additions & 11 deletions

File tree

initrd/etc/functions

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -297,16 +297,32 @@ check_pending_rollback() {
297297
return 0
298298
fi
299299

300-
backup_file="$(cat "$marker_file" 2>/dev/null || true)"
301-
302-
# Stale or corrupt marker (backup gone) - clear it and continue normal boot
303-
if [ -z "$backup_file" ] || [ ! -f "$backup_file" ]; then
304-
warn "Stale rollback marker found (backup not found: $backup_file) - clearing"
300+
# Read first line only to avoid multi-line injection
301+
backup_file="$(head -n 1 "$marker_file" 2>/dev/null || true)"
302+
# Normalize path and validate it stays within /boot/${brand_lower}/
303+
backup_file_resolved="$(readlink -f -- "$backup_file" 2>/dev/null || true)"
304+
305+
# Stale, corrupt, or unsafe marker - clear it and continue normal boot
306+
if [ -z "$backup_file_resolved" ] || [ ! -f "$backup_file_resolved" ]; then
307+
warn "Stale rollback marker found (backup not found: ${backup_file_resolved:-$backup_file}) - clearing"
305308
mount -o remount,rw /boot 2>/dev/null || true
306309
rm -f "$marker_file" 2>/dev/null || true
307310
mount -o remount,ro /boot 2>/dev/null || true
308311
return 0
309312
fi
313+
case "$backup_file_resolved" in
314+
"/boot/${brand_lower}/backup_"*.rom)
315+
# valid path, continue
316+
;;
317+
*)
318+
warn "Invalid rollback marker path '$backup_file_resolved' - clearing"
319+
mount -o remount,rw /boot 2>/dev/null || true
320+
rm -f "$marker_file" 2>/dev/null || true
321+
mount -o remount,ro /boot 2>/dev/null || true
322+
return 0
323+
;;
324+
esac
325+
backup_file="$backup_file_resolved"
310326

311327
DEBUG "pending_rollback found: $backup_file - starting 30-second confirmation countdown"
312328

initrd/init

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -215,18 +215,16 @@ elif [ "$boot_option" = "o" ]; then
215215
# just in case...
216216
exit
217217
elif [ "$boot_option" = "b" ]; then
218-
# Manual emergency rollback: mount /boot, find backup, and reflash.
219-
# Uses the same check_pending_rollback() path (marker-based) or falls
220-
# back to the most recent backup file if no marker is present.
218+
# Manual emergency rollback: mount /boot and invoke marker-based rollback.
219+
# Uses check_pending_rollback() which handles the 30-second countdown,
220+
# --no-backup, and --bypass-verify. If no marker is present it returns
221+
# silently and boot continues normally.
221222
printf '\a'
222223
echo -e "***** Manual rollback requested\n" >/dev/tty0
223224
if [ -n "$CONFIG_BOOT_DEV" ] && [ -e "$CONFIG_BOOT_DEV" ]; then
224225
mount -o ro "$CONFIG_BOOT_DEV" /boot 2>/dev/null || true
225226
fi
226-
# check_pending_rollback handles the 30-second countdown, --no-backup,
227-
# and --bypass-verify. If no marker is found it returns silently.
228227
check_pending_rollback
229-
# If marker was absent or rollback was confirmed (kept), continue normal boot.
230228
fi
231229

232230
if [ "$CONFIG_BASIC" = "y" ]; then

0 commit comments

Comments
 (0)