1#!/bin/sh
2# SPDX-License-Identifier: GPL-2.0
3#
4# Measure kernel stack entropy by sampling via LKDTM's REPORT_STACK test.
5set -e
6samples="${1:-1000}"
7TRIGGER=/sys/kernel/debug/provoke-crash/DIRECT
8KSELFTEST_SKIP_TEST=4
9
10# Verify we have LKDTM available in the kernel.
11if [ ! -r $TRIGGER ] ; then
12	/sbin/modprobe -q lkdtm || true
13	if [ ! -r $TRIGGER ] ; then
14		echo "Cannot find $TRIGGER (missing CONFIG_LKDTM?)"
15	else
16		echo "Cannot write $TRIGGER (need to run as root?)"
17	fi
18	# Skip this test
19	exit $KSELFTEST_SKIP_TEST
20fi
21
22# Capture dmesg continuously since it may fill up depending on sample size.
23log=$(mktemp -t stack-entropy-XXXXXX)
24dmesg --follow >"$log" & pid=$!
25report=-1
26for i in $(seq 1 $samples); do
27        echo "REPORT_STACK" > $TRIGGER
28	if [ -t 1 ]; then
29		percent=$(( 100 * $i / $samples ))
30		if [ "$percent" -ne "$report" ]; then
31			/bin/echo -en "$percent%\r"
32			report="$percent"
33		fi
34	fi
35done
36kill "$pid"
37
38# Count unique offsets since last run.
39seen=$(tac "$log" | grep -m1 -B"$samples"0 'Starting stack offset' | \
40	grep 'Stack offset' | awk '{print $NF}' | sort | uniq -c | wc -l)
41bits=$(echo "obase=2; $seen" | bc | wc -L)
42echo "Bits of stack entropy: $bits"
43rm -f "$log"
44
45# We would expect any functional stack randomization to be at least 5 bits.
46if [ "$bits" -lt 5 ]; then
47	echo "Stack entropy is low! Booted without 'randomize_kstack_offset=y'?"
48	exit 1
49else
50	exit 0
51fi
52