Splux Linux

source-based Linux using SPS

SPS · log · files · refs · tags · releases · people · languages · GitHub · commit

2909919


mkiso: copy the program interpreter to the path the ELF names

Date
Commit2909919b32b591f1864043c4a8b9587d8f0f2bd8
GitHubmirror

Parents

Stat

 bin/mkiso | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 81 insertions(+)

Diff

diff --git a/bin/mkiso b/bin/mkiso
index fff7ea9..0f66851 100755
--- a/bin/mkiso
+++ b/bin/mkiso
@@ -290,9 +290,42 @@ mkiso_copy_libs()
 				esac
 				;;
 		esac
+		# An ldd line reads "WANTED => RESOLVED". For a library, WANTED is
+		# a soname the loader searches for, and copying RESOLVED is right.
+		# For the program interpreter, WANTED is the absolute path baked
+		# into the ELF, and the kernel opens exactly that. When the two
+		# differ because the host reaches the loader through a symlinked
+		# lib64, copying only RESOLVED leaves the interpreter missing at
+		# the one path that matters, and exec fails with ENOENT. The
+		# kernel then reports it as "can't execute /sbin/init".
+		case $mkiso_line in
+			*" => "*)
+				mkiso_wanted=${mkiso_line%% => *}
+				mkiso_wanted=${mkiso_wanted## }
+				mkiso_wanted=${mkiso_wanted#	}
+				case $mkiso_wanted in
+					/*)
+						[ "$mkiso_wanted" = "$mkiso_lib" ] ||
+							mkiso_copy_as "$mkiso_lib" "$mkiso_wanted"
+						;;
+				esac
+				;;
+		esac
 	done
 }
 
+# Place the contents of an existing host file at a specific path in the live
+# root, which may differ from where it lives on the host.
+mkiso_copy_as()
+{
+	mkiso_src=$1
+	mkiso_dst=$2
+	[ -n "$mkiso_src" ] && [ -e "$mkiso_src" ] || return 0
+	[ -e "$mkiso_live$mkiso_dst" ] && return 0
+	mkdir -p "$mkiso_live${mkiso_dst%/*}" || return 0
+	cp -a "$mkiso_src" "$mkiso_live$mkiso_dst" 2>/dev/null || return 0
+}
+
 # close_libs only walks bin/sbin. cc1 (libmpc/libisl) and Mesa DRI
 # (libSPIRV-Tools) are dlopened helpers, so a seeded disc can have gcc
 # and still fail "C compiler cannot create executables", and Plasma can
@@ -1590,6 +1623,54 @@ mkiso_install_pid1()
 	fi
 	[ -x "$mkiso_live/sbin/init" ] ||
 		sps_die "$SPS_EX_PACKAGE" "failed to install /sbin/init"
+	mkiso_verify_init
+}
+
+# /sbin/init existing is not the same as /sbin/init being runnable. A dangling
+# symlink, a missing program interpreter, or a missing shared library all make
+# the kernel fail switch_root with ENOENT, which it reports as "can't execute
+# /sbin/init: No such file or directory". That panic is only visible after the
+# disc is written and booted, so check it here while it is still cheap.
+mkiso_verify_init()
+{
+	mkiso_init_target=$mkiso_live/sbin/init
+	mkiso_init_hops=0
+	while [ -L "$mkiso_init_target" ]; do
+		mkiso_init_hops=$((mkiso_init_hops + 1))
+		[ "$mkiso_init_hops" -lt 10 ] ||
+			sps_die "$SPS_EX_PACKAGE" "/sbin/init is a symlink loop"
+		mkiso_init_link=$(readlink "$mkiso_init_target")
+		case $mkiso_init_link in
+			/*) mkiso_init_target=$mkiso_live$mkiso_init_link ;;
+			*) mkiso_init_target=${mkiso_init_target%/*}/$mkiso_init_link ;;
+		esac
+	done
+	[ -f "$mkiso_init_target" ] ||
+		sps_die "$SPS_EX_PACKAGE" \
+			"/sbin/init resolves to ${mkiso_init_target#$mkiso_live}, which is not in the live root"
+	[ -x "$mkiso_init_target" ] ||
+		sps_die "$SPS_EX_PACKAGE" "/sbin/init is not executable"
+
+	command -v readelf >/dev/null 2>&1 || return 0
+	# readelf prints "  [     0]  /lib64/ld-linux-x86-64.so.2"; take the
+	# whole path after the offset field rather than matching on "ld-",
+	# which a greedy expression would clip to the last path component.
+	mkiso_init_interp=$(readelf -p .interp "$mkiso_init_target" 2>/dev/null |
+		sed -n 's/^[[:space:]]*\[[^]]*\][[:space:]]*\(\/.*\)$/\1/p' |
+		head -n 1)
+	if [ -n "$mkiso_init_interp" ] &&
+		[ ! -e "$mkiso_live$mkiso_init_interp" ]
+	then
+		sps_die "$SPS_EX_PACKAGE" \
+			"PID 1 needs interpreter $mkiso_init_interp, which is not in the live root"
+	fi
+
+	command -v ldd >/dev/null 2>&1 || return 0
+	mkiso_init_missing=$(ldd "$mkiso_init_target" 2>/dev/null |
+		sed -n 's/^[[:space:]]*\([^ ]*\) => not found.*/\1/p')
+	[ -z "$mkiso_init_missing" ] ||
+		printf '%s: warning: PID 1 has unresolved libraries on the host: %s\n' \
+			"$sps_prog" "$(printf '%s' "$mkiso_init_missing" | tr '\n' ' ')" >&2
 }
 
 # --- live root contents -------------------------------------------------