162306a36Sopenharmony_ci#!/bin/sh
262306a36Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0
362306a36Sopenharmony_ci#
462306a36Sopenharmony_ci# Measure kernel stack entropy by sampling via LKDTM's REPORT_STACK test.
562306a36Sopenharmony_ciset -e
662306a36Sopenharmony_cisamples="${1:-1000}"
762306a36Sopenharmony_ciTRIGGER=/sys/kernel/debug/provoke-crash/DIRECT
862306a36Sopenharmony_ciKSELFTEST_SKIP_TEST=4
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci# Verify we have LKDTM available in the kernel.
1162306a36Sopenharmony_ciif [ ! -r $TRIGGER ] ; then
1262306a36Sopenharmony_ci	/sbin/modprobe -q lkdtm || true
1362306a36Sopenharmony_ci	if [ ! -r $TRIGGER ] ; then
1462306a36Sopenharmony_ci		echo "Cannot find $TRIGGER (missing CONFIG_LKDTM?)"
1562306a36Sopenharmony_ci	else
1662306a36Sopenharmony_ci		echo "Cannot write $TRIGGER (need to run as root?)"
1762306a36Sopenharmony_ci	fi
1862306a36Sopenharmony_ci	# Skip this test
1962306a36Sopenharmony_ci	exit $KSELFTEST_SKIP_TEST
2062306a36Sopenharmony_cifi
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci# Capture dmesg continuously since it may fill up depending on sample size.
2362306a36Sopenharmony_cilog=$(mktemp -t stack-entropy-XXXXXX)
2462306a36Sopenharmony_cidmesg --follow >"$log" & pid=$!
2562306a36Sopenharmony_cireport=-1
2662306a36Sopenharmony_cifor i in $(seq 1 $samples); do
2762306a36Sopenharmony_ci        echo "REPORT_STACK" > $TRIGGER
2862306a36Sopenharmony_ci	if [ -t 1 ]; then
2962306a36Sopenharmony_ci		percent=$(( 100 * $i / $samples ))
3062306a36Sopenharmony_ci		if [ "$percent" -ne "$report" ]; then
3162306a36Sopenharmony_ci			/bin/echo -en "$percent%\r"
3262306a36Sopenharmony_ci			report="$percent"
3362306a36Sopenharmony_ci		fi
3462306a36Sopenharmony_ci	fi
3562306a36Sopenharmony_cidone
3662306a36Sopenharmony_cikill "$pid"
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci# Count unique offsets since last run.
3962306a36Sopenharmony_ciseen=$(tac "$log" | grep -m1 -B"$samples"0 'Starting stack offset' | \
4062306a36Sopenharmony_ci	grep 'Stack offset' | awk '{print $NF}' | sort | uniq -c | wc -l)
4162306a36Sopenharmony_cibits=$(echo "obase=2; $seen" | bc | wc -L)
4262306a36Sopenharmony_ciecho "Bits of stack entropy: $bits"
4362306a36Sopenharmony_cirm -f "$log"
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci# We would expect any functional stack randomization to be at least 5 bits.
4662306a36Sopenharmony_ciif [ "$bits" -lt 5 ]; then
4762306a36Sopenharmony_ci	echo "Stack entropy is low! Booted without 'randomize_kstack_offset=y'?"
4862306a36Sopenharmony_ci	exit 1
4962306a36Sopenharmony_cielse
5062306a36Sopenharmony_ci	exit 0
5162306a36Sopenharmony_cifi
52