1*190c4546SIan Rogers#!/bin/bash 2*190c4546SIan Rogers# SPDX-License-Identifier: GPL-2.0 3*190c4546SIan Rogers# perf inject --aslr test 4*190c4546SIan Rogers 5*190c4546SIan Rogersset -e 6*190c4546SIan Rogersset -o pipefail 7*190c4546SIan Rogers 8*190c4546SIan Rogersshelldir=$(dirname "$0") 9*190c4546SIan Rogers# shellcheck source=lib/perf_has_symbol.sh 10*190c4546SIan Rogers. "${shelldir}"/lib/perf_has_symbol.sh 11*190c4546SIan Rogers 12*190c4546SIan Rogerssym="noploop" 13*190c4546SIan Rogers 14*190c4546SIan Rogersskip_test_missing_symbol ${sym} 15*190c4546SIan Rogers 16*190c4546SIan Rogers# Create global temp directory 17*190c4546SIan Rogerstemp_dir=$(mktemp -d /tmp/perf-test-aslr.XXXXXXXXXX) 18*190c4546SIan Rogers 19*190c4546SIan Rogersprog="perf test -w noploop" 20*190c4546SIan Rogers[ "$(uname -m)" = "s390x" ] && prog="$prog 3" 21*190c4546SIan Rogerserr=0 22*190c4546SIan Rogerskprog="dd if=/dev/urandom of=/dev/null bs=1M count=50" 23*190c4546SIan Rogers 24*190c4546SIan Rogerscleanup() { 25*190c4546SIan Rogers local exit_code=${1:-$?} 26*190c4546SIan Rogers trap - EXIT TERM INT 27*190c4546SIan Rogers if [ "${exit_code}" -ne 0 ] || [ "${err}" -ne 0 ]; then 28*190c4546SIan Rogers echo "Test failed! Preserving temp directory: ${temp_dir}" 29*190c4546SIan Rogers return 30*190c4546SIan Rogers fi 31*190c4546SIan Rogers # Check if temp_dir is set and looks sane before removing 32*190c4546SIan Rogers if [[ "${temp_dir}" =~ ^/tmp/perf-test-aslr\. ]]; then 33*190c4546SIan Rogers rm -rf "${temp_dir}" 34*190c4546SIan Rogers fi 35*190c4546SIan Rogers} 36*190c4546SIan Rogers 37*190c4546SIan Rogerstrap_cleanup() { 38*190c4546SIan Rogers local exit_code=$? 39*190c4546SIan Rogers echo "Unexpected signal in ${FUNCNAME[1]}" 40*190c4546SIan Rogers cleanup ${exit_code} 41*190c4546SIan Rogers exit ${exit_code} 42*190c4546SIan Rogers} 43*190c4546SIan Rogerstrap trap_cleanup EXIT TERM INT 44*190c4546SIan Rogers 45*190c4546SIan Rogersget_noploop_addr() { 46*190c4546SIan Rogers local file=$1 47*190c4546SIan Rogers perf script -i "$file" | awk ' 48*190c4546SIan Rogers BEGIN { found=0 } 49*190c4546SIan Rogers { 50*190c4546SIan Rogers for (i=1; i<=NF; i++) { 51*190c4546SIan Rogers if ($i ~ /noploop\+/) { 52*190c4546SIan Rogers if (!found) { 53*190c4546SIan Rogers print $(i-1) 54*190c4546SIan Rogers found=1 55*190c4546SIan Rogers } 56*190c4546SIan Rogers } 57*190c4546SIan Rogers } 58*190c4546SIan Rogers }' 59*190c4546SIan Rogers} 60*190c4546SIan Rogers 61*190c4546SIan Rogerstest_basic_aslr() { 62*190c4546SIan Rogers echo "Test basic ASLR remapping" 63*190c4546SIan Rogers local data 64*190c4546SIan Rogers data=$(mktemp "${temp_dir}/perf.data.basic.XXXXXX") 65*190c4546SIan Rogers local data2 66*190c4546SIan Rogers data2=$(mktemp "${temp_dir}/perf.data2.basic.XXXXXX") 67*190c4546SIan Rogers 68*190c4546SIan Rogers perf record -e task-clock:u -o "${data}" ${prog} 69*190c4546SIan Rogers perf inject -v --aslr -i "${data}" -o "${data2}" 70*190c4546SIan Rogers 71*190c4546SIan Rogers orig_addr=$(get_noploop_addr "${data}") 72*190c4546SIan Rogers new_addr=$(get_noploop_addr "${data2}") 73*190c4546SIan Rogers 74*190c4546SIan Rogers echo "Basic ASLR: orig_addr=$orig_addr, new_addr=$new_addr" 75*190c4546SIan Rogers 76*190c4546SIan Rogers if [ -z "$orig_addr" ]; then 77*190c4546SIan Rogers echo "Basic ASLR test [Failed - no noploop samples in original file]" 78*190c4546SIan Rogers err=1 79*190c4546SIan Rogers elif [ -z "$new_addr" ]; then 80*190c4546SIan Rogers echo "Basic ASLR test [Failed - could not find remapped address]" 81*190c4546SIan Rogers err=1 82*190c4546SIan Rogers elif [ "$orig_addr" = "$new_addr" ]; then 83*190c4546SIan Rogers echo "Basic ASLR test [Failed - addresses are not remapped]" 84*190c4546SIan Rogers err=1 85*190c4546SIan Rogers else 86*190c4546SIan Rogers echo "Basic ASLR test [Success]" 87*190c4546SIan Rogers fi 88*190c4546SIan Rogers} 89*190c4546SIan Rogers 90*190c4546SIan Rogerstest_pipe_aslr() { 91*190c4546SIan Rogers echo "Test pipe mode ASLR remapping" 92*190c4546SIan Rogers local data 93*190c4546SIan Rogers data=$(mktemp "${temp_dir}/perf.data.pipe.XXXXXX") 94*190c4546SIan Rogers local data2 95*190c4546SIan Rogers data2=$(mktemp "${temp_dir}/perf.data2.pipe.XXXXXX") 96*190c4546SIan Rogers 97*190c4546SIan Rogers # Use tee to save the original pipe data for comparison 98*190c4546SIan Rogers perf record -e task-clock:u -o - ${prog} | tee "${data}" | perf inject --aslr -o "${data2}" 99*190c4546SIan Rogers 100*190c4546SIan Rogers orig_addr=$(get_noploop_addr "${data}") 101*190c4546SIan Rogers new_addr=$(get_noploop_addr "${data2}") 102*190c4546SIan Rogers 103*190c4546SIan Rogers echo "Pipe ASLR: orig_addr=$orig_addr, new_addr=$new_addr" 104*190c4546SIan Rogers 105*190c4546SIan Rogers if [ -z "$orig_addr" ]; then 106*190c4546SIan Rogers echo "Pipe ASLR test [Failed - no noploop samples in original file]" 107*190c4546SIan Rogers err=1 108*190c4546SIan Rogers elif [ -z "$new_addr" ]; then 109*190c4546SIan Rogers echo "Pipe ASLR test [Failed - could not find remapped address]" 110*190c4546SIan Rogers err=1 111*190c4546SIan Rogers elif [ "$orig_addr" = "$new_addr" ]; then 112*190c4546SIan Rogers echo "Pipe ASLR test [Failed - addresses are not remapped]" 113*190c4546SIan Rogers err=1 114*190c4546SIan Rogers else 115*190c4546SIan Rogers echo "Pipe ASLR test [Success]" 116*190c4546SIan Rogers fi 117*190c4546SIan Rogers} 118*190c4546SIan Rogers 119*190c4546SIan Rogerstest_callchain_aslr() { 120*190c4546SIan Rogers echo "Test Callchain ASLR remapping" 121*190c4546SIan Rogers local data 122*190c4546SIan Rogers data=$(mktemp "${temp_dir}/perf.data.callchain.XXXXXX") 123*190c4546SIan Rogers local data2 124*190c4546SIan Rogers data2=$(mktemp "${temp_dir}/perf.data2.callchain.XXXXXX") 125*190c4546SIan Rogers 126*190c4546SIan Rogers perf record -g -e task-clock:u -o "${data}" ${prog} 127*190c4546SIan Rogers perf inject --aslr -i "${data}" -o "${data2}" 128*190c4546SIan Rogers 129*190c4546SIan Rogers orig_addr=$(get_noploop_addr "${data}") 130*190c4546SIan Rogers new_addr=$(get_noploop_addr "${data2}") 131*190c4546SIan Rogers 132*190c4546SIan Rogers echo "Callchain ASLR: orig_addr=$orig_addr, new_addr=$new_addr" 133*190c4546SIan Rogers 134*190c4546SIan Rogers if [ -z "$orig_addr" ]; then 135*190c4546SIan Rogers echo "Callchain ASLR test [Failed - no noploop samples in original file]" 136*190c4546SIan Rogers err=1 137*190c4546SIan Rogers elif [ -z "$new_addr" ]; then 138*190c4546SIan Rogers echo "Callchain ASLR test [Failed - could not find remapped address]" 139*190c4546SIan Rogers err=1 140*190c4546SIan Rogers elif [ "$orig_addr" = "$new_addr" ]; then 141*190c4546SIan Rogers echo "Callchain ASLR test [Failed - addresses are not remapped]" 142*190c4546SIan Rogers err=1 143*190c4546SIan Rogers else 144*190c4546SIan Rogers # Extract callchain addresses (indented lines starting with hex addresses) 145*190c4546SIan Rogers orig_callchain=$(perf script -i "${data}" | awk '/^[[:space:]]+[0-9a-f]+/ {print $1}') 146*190c4546SIan Rogers new_callchain=$(perf script -i "${data2}" | awk '/^[[:space:]]+[0-9a-f]+/ {print $1}') 147*190c4546SIan Rogers 148*190c4546SIan Rogers if [ -z "$orig_callchain" ]; then 149*190c4546SIan Rogers echo "Callchain ASLR test [Failed - no callchain samples in original file]" 150*190c4546SIan Rogers err=1 151*190c4546SIan Rogers elif [ -z "$new_callchain" ]; then 152*190c4546SIan Rogers echo "Callchain ASLR test [Failed - callchain data was dropped]" 153*190c4546SIan Rogers err=1 154*190c4546SIan Rogers elif [ "$orig_callchain" = "$new_callchain" ]; then 155*190c4546SIan Rogers echo "Callchain ASLR test [Failed - callchain addresses were not remapped]" 156*190c4546SIan Rogers err=1 157*190c4546SIan Rogers else 158*190c4546SIan Rogers echo "Callchain ASLR test [Success]" 159*190c4546SIan Rogers fi 160*190c4546SIan Rogers fi 161*190c4546SIan Rogers} 162*190c4546SIan Rogers 163*190c4546SIan Rogerstest_report_aslr() { 164*190c4546SIan Rogers echo "Test perf report consistency" 165*190c4546SIan Rogers local data 166*190c4546SIan Rogers data=$(mktemp "${temp_dir}/perf.data.report.XXXXXX") 167*190c4546SIan Rogers local data2 168*190c4546SIan Rogers data2=$(mktemp "${temp_dir}/perf.data2.report.XXXXXX") 169*190c4546SIan Rogers local data_clean 170*190c4546SIan Rogers data_clean=$(mktemp "${temp_dir}/perf.data.clean.XXXXXX") 171*190c4546SIan Rogers 172*190c4546SIan Rogers perf record -e task-clock:u -o "${data}" ${prog} 173*190c4546SIan Rogers # Use -b to inject build-ids and force ordered events processing in both 174*190c4546SIan Rogers perf inject -b -i "${data}" -o "${data_clean}" 175*190c4546SIan Rogers perf inject -v -b --aslr -i "${data}" -o "${data2}" 176*190c4546SIan Rogers 177*190c4546SIan Rogers local report1="${temp_dir}/report1_basic" 178*190c4546SIan Rogers local report2="${temp_dir}/report2_basic" 179*190c4546SIan Rogers local report1_clean="${temp_dir}/report1_basic.clean" 180*190c4546SIan Rogers local report2_clean="${temp_dir}/report2_basic.clean" 181*190c4546SIan Rogers local diff_file="${temp_dir}/diff_basic" 182*190c4546SIan Rogers 183*190c4546SIan Rogers perf report -i "${data_clean}" --stdio > "${report1}" 184*190c4546SIan Rogers perf report -i "${data2}" --stdio > "${report2}" 185*190c4546SIan Rogers 186*190c4546SIan Rogers # Strip headers and compare lines with percentages 187*190c4546SIan Rogers grep '%' "${report1}" | grep -v '^#' | \ 188*190c4546SIan Rogers grep -v -E '0x[0-9a-f]{8,}|0000000000000000' | sort > "${report1_clean}" || true 189*190c4546SIan Rogers grep '%' "${report2}" | grep -v '^#' | \ 190*190c4546SIan Rogers grep -v -E '0x[0-9a-f]{8,}|0000000000000000' | sort > "${report2_clean}" || true 191*190c4546SIan Rogers 192*190c4546SIan Rogers diff -u -w "${report1_clean}" "${report2_clean}" > "${diff_file}" || true 193*190c4546SIan Rogers 194*190c4546SIan Rogers if [ ! -s "${report1_clean}" ]; then 195*190c4546SIan Rogers echo "Report ASLR test [Failed - no samples captured]" 196*190c4546SIan Rogers err=1 197*190c4546SIan Rogers elif [ -s "${diff_file}" ]; then 198*190c4546SIan Rogers echo "Report ASLR test [Failed - reports differ]" 199*190c4546SIan Rogers echo "Showing first 20 lines of diff:" 200*190c4546SIan Rogers head -n 20 "${diff_file}" 201*190c4546SIan Rogers err=1 202*190c4546SIan Rogers else 203*190c4546SIan Rogers echo "Report ASLR test [Success]" 204*190c4546SIan Rogers fi 205*190c4546SIan Rogers} 206*190c4546SIan Rogers 207*190c4546SIan Rogerstest_pipe_report_aslr() { 208*190c4546SIan Rogers echo "Test pipe mode perf report consistency" 209*190c4546SIan Rogers local data 210*190c4546SIan Rogers data=$(mktemp "${temp_dir}/perf.data.pipe_report.XXXXXX") 211*190c4546SIan Rogers local data2 212*190c4546SIan Rogers data2=$(mktemp "${temp_dir}/perf.data2.pipe_report.XXXXXX") 213*190c4546SIan Rogers local data_clean 214*190c4546SIan Rogers data_clean=$(mktemp "${temp_dir}/perf.data.clean.XXXXXX") 215*190c4546SIan Rogers 216*190c4546SIan Rogers # Use tee to save the original pipe data, then process it with inject -b 217*190c4546SIan Rogers perf record -e task-clock:u -o - ${prog} | \ 218*190c4546SIan Rogers tee "${data}" | \ 219*190c4546SIan Rogers perf inject -b --aslr -o "${data2}" 220*190c4546SIan Rogers perf inject -b -i "${data}" -o "${data_clean}" 221*190c4546SIan Rogers 222*190c4546SIan Rogers local report1="${temp_dir}/report1_pipe" 223*190c4546SIan Rogers local report2="${temp_dir}/report2_pipe" 224*190c4546SIan Rogers local report1_clean="${temp_dir}/report1_pipe.clean" 225*190c4546SIan Rogers local report2_clean="${temp_dir}/report2_pipe.clean" 226*190c4546SIan Rogers local diff_file="${temp_dir}/diff_pipe" 227*190c4546SIan Rogers 228*190c4546SIan Rogers perf report -i "${data_clean}" --stdio > "${report1}" 229*190c4546SIan Rogers perf report -i "${data2}" --stdio > "${report2}" 230*190c4546SIan Rogers 231*190c4546SIan Rogers # Strip headers and compare lines with percentages 232*190c4546SIan Rogers grep '%' "${report1}" | grep -v '^#' | \ 233*190c4546SIan Rogers grep -v -E '0x[0-9a-f]{8,}|0000000000000000' | sort > "${report1_clean}" || true 234*190c4546SIan Rogers grep '%' "${report2}" | grep -v '^#' | \ 235*190c4546SIan Rogers grep -v -E '0x[0-9a-f]{8,}|0000000000000000' | sort > "${report2_clean}" || true 236*190c4546SIan Rogers 237*190c4546SIan Rogers diff -u -w "${report1_clean}" "${report2_clean}" > "${diff_file}" || true 238*190c4546SIan Rogers 239*190c4546SIan Rogers if [ ! -s "${report1_clean}" ]; then 240*190c4546SIan Rogers echo "Pipe Report ASLR test [Failed - no samples captured]" 241*190c4546SIan Rogers err=1 242*190c4546SIan Rogers elif [ -s "${diff_file}" ]; then 243*190c4546SIan Rogers echo "Pipe Report ASLR test [Failed - reports differ]" 244*190c4546SIan Rogers echo "Showing first 20 lines of diff:" 245*190c4546SIan Rogers head -n 20 "${diff_file}" 246*190c4546SIan Rogers err=1 247*190c4546SIan Rogers else 248*190c4546SIan Rogers echo "Pipe Report ASLR test [Success]" 249*190c4546SIan Rogers fi 250*190c4546SIan Rogers} 251*190c4546SIan Rogers 252*190c4546SIan Rogerstest_pipe_out_report_aslr() { 253*190c4546SIan Rogers echo "Test pipe output mode perf report consistency" 254*190c4546SIan Rogers local data 255*190c4546SIan Rogers data=$(mktemp "${temp_dir}/perf.data.pipe_out_report.XXXXXX") 256*190c4546SIan Rogers local data_clean 257*190c4546SIan Rogers data_clean=$(mktemp "${temp_dir}/perf.data.clean.XXXXXX") 258*190c4546SIan Rogers 259*190c4546SIan Rogers perf record -e task-clock:u -o "${data}" ${prog} 260*190c4546SIan Rogers perf inject -b -i "${data}" -o "${data_clean}" 261*190c4546SIan Rogers 262*190c4546SIan Rogers local report1="${temp_dir}/report1_pipe_out" 263*190c4546SIan Rogers local report2="${temp_dir}/report2_pipe_out" 264*190c4546SIan Rogers local report1_clean="${temp_dir}/report1_pipe_out.clean" 265*190c4546SIan Rogers local report2_clean="${temp_dir}/report2_pipe_out.clean" 266*190c4546SIan Rogers local diff_file="${temp_dir}/diff_pipe_out" 267*190c4546SIan Rogers 268*190c4546SIan Rogers perf report -i "${data_clean}" --stdio > "${report1}" 269*190c4546SIan Rogers perf inject -b --aslr -i "${data}" -o - | perf report -i - --stdio > "${report2}" 270*190c4546SIan Rogers 271*190c4546SIan Rogers # Strip headers and compare lines with percentages 272*190c4546SIan Rogers grep '%' "${report1}" | grep -v '^#' | \ 273*190c4546SIan Rogers grep -v -E '0x[0-9a-f]{8,}|0000000000000000' | sort > "${report1_clean}" || true 274*190c4546SIan Rogers grep '%' "${report2}" | grep -v '^#' | \ 275*190c4546SIan Rogers grep -v -E '0x[0-9a-f]{8,}|0000000000000000' | sort > "${report2_clean}" || true 276*190c4546SIan Rogers 277*190c4546SIan Rogers diff -u -w "${report1_clean}" "${report2_clean}" > "${diff_file}" || true 278*190c4546SIan Rogers 279*190c4546SIan Rogers if [ ! -s "${report1_clean}" ]; then 280*190c4546SIan Rogers echo "Pipe Output Report ASLR test [Failed - no samples captured]" 281*190c4546SIan Rogers err=1 282*190c4546SIan Rogers elif [ -s "${diff_file}" ]; then 283*190c4546SIan Rogers echo "Pipe Output Report ASLR test [Failed - reports differ]" 284*190c4546SIan Rogers echo "Showing first 20 lines of diff:" 285*190c4546SIan Rogers head -n 20 "${diff_file}" 286*190c4546SIan Rogers err=1 287*190c4546SIan Rogers else 288*190c4546SIan Rogers echo "Pipe Output Report ASLR test [Success]" 289*190c4546SIan Rogers fi 290*190c4546SIan Rogers} 291*190c4546SIan Rogers 292*190c4546SIan Rogerstest_dropped_samples() { 293*190c4546SIan Rogers echo "Test dropped samples (phys-data)" 294*190c4546SIan Rogers local data 295*190c4546SIan Rogers data=$(mktemp "${temp_dir}/perf.data.dropped.XXXXXX") 296*190c4546SIan Rogers local data2 297*190c4546SIan Rogers data2=$(mktemp "${temp_dir}/perf.data2.dropped.XXXXXX") 298*190c4546SIan Rogers 299*190c4546SIan Rogers # Check if --phys-data is supported by recording a short run 300*190c4546SIan Rogers if ! perf record -e task-clock:u --phys-data -o "${data}" -- sleep 0.1 > /dev/null 2>&1; then 301*190c4546SIan Rogers echo "Skipping dropped samples test as --phys-data is not supported" 302*190c4546SIan Rogers return 303*190c4546SIan Rogers fi 304*190c4546SIan Rogers 305*190c4546SIan Rogers perf record -e task-clock:u --phys-data -o "${data}" ${prog} 306*190c4546SIan Rogers perf inject --aslr -i "${data}" -o "${data2}" 307*190c4546SIan Rogers 308*190c4546SIan Rogers # Verify that the original file actually contained samples! 309*190c4546SIan Rogers orig_samples=$(perf script -i "${data}" | wc -l) 310*190c4546SIan Rogers if [ "$orig_samples" -eq 0 ]; then 311*190c4546SIan Rogers echo "Dropped samples test [Failed - no samples in original file]" 312*190c4546SIan Rogers err=1 313*190c4546SIan Rogers else 314*190c4546SIan Rogers # Verify that samples are dropped. 315*190c4546SIan Rogers samples_count=$(perf script -i "${data2}" | wc -l) 316*190c4546SIan Rogers 317*190c4546SIan Rogers if [ "$samples_count" -gt 0 ]; then 318*190c4546SIan Rogers echo "Dropped samples test [Failed - samples were not dropped]" 319*190c4546SIan Rogers err=1 320*190c4546SIan Rogers else 321*190c4546SIan Rogers echo "Dropped samples test [Success]" 322*190c4546SIan Rogers fi 323*190c4546SIan Rogers fi 324*190c4546SIan Rogers} 325*190c4546SIan Rogers 326*190c4546SIan Rogerstest_kernel_aslr() { 327*190c4546SIan Rogers echo "Test kernel ASLR remapping" 328*190c4546SIan Rogers local kdata 329*190c4546SIan Rogers kdata=$(mktemp "${temp_dir}/perf.data.kernel.XXXXXX") 330*190c4546SIan Rogers local kdata2 331*190c4546SIan Rogers kdata2=$(mktemp "${temp_dir}/perf.data2.kernel.XXXXXX") 332*190c4546SIan Rogers local log_file 333*190c4546SIan Rogers log_file=$(mktemp "${temp_dir}/kernel_record.log.XXXXXX") 334*190c4546SIan Rogers 335*190c4546SIan Rogers # Try to record kernel samples 336*190c4546SIan Rogers if ! perf record -e task-clock:k -o "${kdata}" ${kprog} > "${log_file}" 2>&1; then 337*190c4546SIan Rogers echo "Skipping kernel ASLR test as recording failed (maybe no permissions)" 338*190c4546SIan Rogers return 339*190c4546SIan Rogers fi 340*190c4546SIan Rogers 341*190c4546SIan Rogers # Check for warning about kernel map restriction 342*190c4546SIan Rogers if grep -q "Couldn't record kernel reference relocation symbol" "${log_file}"; then 343*190c4546SIan Rogers echo "Skipping kernel ASLR test as kernel map could not be recorded (permissions restricted)" 344*190c4546SIan Rogers return 345*190c4546SIan Rogers fi 346*190c4546SIan Rogers 347*190c4546SIan Rogers perf inject -v --aslr -i "${kdata}" -o "${kdata2}" 348*190c4546SIan Rogers 349*190c4546SIan Rogers # Check if kernel addresses are remapped. 350*190c4546SIan Rogers # Find the field that ends with :k: (the event name) and take the next field! 351*190c4546SIan Rogers orig_addr=$(perf script -i "${kdata}" | awk ' 352*190c4546SIan Rogers BEGIN { found=0 } 353*190c4546SIan Rogers { 354*190c4546SIan Rogers for (i=1; i<NF; i++) { 355*190c4546SIan Rogers if ($i ~ /:[k]+:?$/) { 356*190c4546SIan Rogers if (!found) { 357*190c4546SIan Rogers print $(i+1) 358*190c4546SIan Rogers found=1 359*190c4546SIan Rogers } 360*190c4546SIan Rogers } 361*190c4546SIan Rogers } 362*190c4546SIan Rogers }') 363*190c4546SIan Rogers new_addr=$(perf script -i "${kdata2}" | awk ' 364*190c4546SIan Rogers BEGIN { found=0 } 365*190c4546SIan Rogers { 366*190c4546SIan Rogers for (i=1; i<NF; i++) { 367*190c4546SIan Rogers if ($i ~ /:[k]+:?$/) { 368*190c4546SIan Rogers if (!found) { 369*190c4546SIan Rogers print $(i+1) 370*190c4546SIan Rogers found=1 371*190c4546SIan Rogers } 372*190c4546SIan Rogers } 373*190c4546SIan Rogers } 374*190c4546SIan Rogers }') 375*190c4546SIan Rogers 376*190c4546SIan Rogers echo "Kernel ASLR: orig_addr=$orig_addr, new_addr=$new_addr" 377*190c4546SIan Rogers 378*190c4546SIan Rogers if [ -z "$orig_addr" ]; then 379*190c4546SIan Rogers echo "Kernel ASLR test [Failed - no kernel samples in original file]" 380*190c4546SIan Rogers err=1 381*190c4546SIan Rogers elif [ -z "$new_addr" ]; then 382*190c4546SIan Rogers echo "Kernel ASLR test [Failed - could not find remapped address]" 383*190c4546SIan Rogers err=1 384*190c4546SIan Rogers elif [ "$orig_addr" = "$new_addr" ]; then 385*190c4546SIan Rogers echo "Kernel ASLR test [Failed - addresses are not remapped]" 386*190c4546SIan Rogers err=1 387*190c4546SIan Rogers else 388*190c4546SIan Rogers echo "Kernel ASLR test [Success]" 389*190c4546SIan Rogers fi 390*190c4546SIan Rogers} 391*190c4546SIan Rogers 392*190c4546SIan Rogerstest_kernel_report_aslr() { 393*190c4546SIan Rogers echo "Test kernel perf report consistency" 394*190c4546SIan Rogers local kdata 395*190c4546SIan Rogers kdata=$(mktemp "${temp_dir}/perf.data.kernel_report.XXXXXX") 396*190c4546SIan Rogers local kdata2 397*190c4546SIan Rogers kdata2=$(mktemp "${temp_dir}/perf.data2.kernel_report.XXXXXX") 398*190c4546SIan Rogers local data_clean 399*190c4546SIan Rogers data_clean=$(mktemp "${temp_dir}/perf.data.clean.XXXXXX") 400*190c4546SIan Rogers local log_file 401*190c4546SIan Rogers log_file=$(mktemp "${temp_dir}/kernel_report_record.log.XXXXXX") 402*190c4546SIan Rogers 403*190c4546SIan Rogers # Try to record kernel samples 404*190c4546SIan Rogers if ! perf record -e task-clock:k -o "${kdata}" ${kprog} > "${log_file}" 2>&1; then 405*190c4546SIan Rogers echo "Skipping kernel report test as recording failed (maybe no permissions)" 406*190c4546SIan Rogers return 407*190c4546SIan Rogers fi 408*190c4546SIan Rogers 409*190c4546SIan Rogers # Check for warning about kernel map restriction 410*190c4546SIan Rogers if grep -q "Couldn't record kernel reference relocation symbol" "${log_file}"; then 411*190c4546SIan Rogers echo "Skipping kernel report test as kernel map could not be recorded (permissions restricted)" 412*190c4546SIan Rogers return 413*190c4546SIan Rogers fi 414*190c4546SIan Rogers 415*190c4546SIan Rogers # Use -b to inject build-ids and force ordered events processing in both 416*190c4546SIan Rogers perf inject -b -i "${kdata}" -o "${data_clean}" 417*190c4546SIan Rogers perf inject -v -b --aslr -i "${kdata}" -o "${kdata2}" 418*190c4546SIan Rogers 419*190c4546SIan Rogers local report1="${temp_dir}/report_kernel1" 420*190c4546SIan Rogers local report2="${temp_dir}/report_kernel2" 421*190c4546SIan Rogers local report1_clean="${temp_dir}/report_kernel1.clean" 422*190c4546SIan Rogers local report2_clean="${temp_dir}/report_kernel2.clean" 423*190c4546SIan Rogers 424*190c4546SIan Rogers perf report -i "${data_clean}" --stdio > "${report1}" 425*190c4546SIan Rogers perf report -i "${kdata2}" --stdio > "${report2}" 426*190c4546SIan Rogers 427*190c4546SIan Rogers # Strip headers and compare lines with percentages 428*190c4546SIan Rogers grep '%' "${report1}" | grep -v '^#' > "${report1_clean}" || true 429*190c4546SIan Rogers grep '%' "${report2}" | grep -v '^#' > "${report2_clean}" || true 430*190c4546SIan Rogers 431*190c4546SIan Rogers # Normalize kernel DSOs and addresses in clean reports 432*190c4546SIan Rogers # This allows kernel modules to be either a module or kernel.kallsyms 433*190c4546SIan Rogers local report1_norm="${temp_dir}/report_kernel1.norm" 434*190c4546SIan Rogers local report2_norm="${temp_dir}/report_kernel2.norm" 435*190c4546SIan Rogers local diff_file="${temp_dir}/diff_kernel" 436*190c4546SIan Rogers 437*190c4546SIan Rogers grep -v -E '0x[0-9a-f]{8,}|0000000000000000' "${report1_clean}" | \ 438*190c4546SIan Rogers awk '{gsub(/\[[a-zA-Z0-9_.-]{2,}\](\.[a-zA-Z0-9_]+)?/, "[kernel]", $0); print}' | \ 439*190c4546SIan Rogers sort > "${report1_norm}" || true 440*190c4546SIan Rogers grep -v -E '0x[0-9a-f]{8,}|0000000000000000' "${report2_clean}" | \ 441*190c4546SIan Rogers awk '{gsub(/\[[a-zA-Z0-9_.-]{2,}\](\.[a-zA-Z0-9_]+)?/, "[kernel]", $0); print}' | \ 442*190c4546SIan Rogers sort > "${report2_norm}" || true 443*190c4546SIan Rogers 444*190c4546SIan Rogers diff -u -w "${report1_norm}" "${report2_norm}" > "${diff_file}" || true 445*190c4546SIan Rogers 446*190c4546SIan Rogers if [ ! -s "${report1_norm}" ]; then 447*190c4546SIan Rogers echo "Kernel Report ASLR test [Failed - no samples captured]" 448*190c4546SIan Rogers err=1 449*190c4546SIan Rogers elif [ -s "${diff_file}" ]; then 450*190c4546SIan Rogers echo "Kernel Report ASLR test [Failed - reports differ]" 451*190c4546SIan Rogers echo "Showing first 20 lines of diff:" 452*190c4546SIan Rogers head -n 20 "${diff_file}" 453*190c4546SIan Rogers err=1 454*190c4546SIan Rogers else 455*190c4546SIan Rogers echo "Kernel Report ASLR test [Success]" 456*190c4546SIan Rogers fi 457*190c4546SIan Rogers} 458*190c4546SIan Rogers 459*190c4546SIan Rogerstest_regs_stripping() { 460*190c4546SIan Rogers echo "Test user register stripping" 461*190c4546SIan Rogers local rdata="${temp_dir}/perf.data.regs" 462*190c4546SIan Rogers local rdata2="${temp_dir}/perf.data.regs.injected" 463*190c4546SIan Rogers local rdata_clean="${temp_dir}/perf.data.regs.clean" 464*190c4546SIan Rogers 465*190c4546SIan Rogers if ! perf record -e cycles:u --user-regs -o "${rdata}" ${prog} > /dev/null 2>&1; then 466*190c4546SIan Rogers echo "Skipping user registers test as recording failed (unsupported flag/platform)" 467*190c4546SIan Rogers return 468*190c4546SIan Rogers fi 469*190c4546SIan Rogers 470*190c4546SIan Rogers perf inject -b -i "${rdata}" -o "${rdata_clean}" 471*190c4546SIan Rogers perf inject -v -b --aslr -i "${rdata}" -o "${rdata2}" 472*190c4546SIan Rogers 473*190c4546SIan Rogers local report1="${temp_dir}/report_regs1" 474*190c4546SIan Rogers local report2="${temp_dir}/report_regs2" 475*190c4546SIan Rogers local report1_clean="${temp_dir}/report_regs1.clean" 476*190c4546SIan Rogers local report2_clean="${temp_dir}/report_regs2.clean" 477*190c4546SIan Rogers local diff_file="${temp_dir}/diff_regs" 478*190c4546SIan Rogers 479*190c4546SIan Rogers perf report -i "${rdata_clean}" --stdio > "${report1}" 2>/dev/null || true 480*190c4546SIan Rogers perf report -i "${rdata2}" --stdio > "${report2}" 2>/dev/null || true 481*190c4546SIan Rogers 482*190c4546SIan Rogers grep '%' "${report1}" | grep -v '^#' | \ 483*190c4546SIan Rogers grep -v -E '0x[0-9a-f]{8,}|0000000000000000' | \ 484*190c4546SIan Rogers sort > "${report1_clean}" || true 485*190c4546SIan Rogers grep '%' "${report2}" | grep -v '^#' | \ 486*190c4546SIan Rogers grep -v -E '0x[0-9a-f]{8,}|0000000000000000' | \ 487*190c4546SIan Rogers sort > "${report2_clean}" || true 488*190c4546SIan Rogers 489*190c4546SIan Rogers diff -u -w "${report1_clean}" "${report2_clean}" > "${diff_file}" || true 490*190c4546SIan Rogers 491*190c4546SIan Rogers if [ ! -s "${report1_clean}" ]; then 492*190c4546SIan Rogers echo "User registers stripping test [Failed - profile trace starved/empty]" 493*190c4546SIan Rogers err=1 494*190c4546SIan Rogers return 495*190c4546SIan Rogers elif [ -s "${diff_file}" ]; then 496*190c4546SIan Rogers echo "User registers stripping test [Failed - report parsing differs]" 497*190c4546SIan Rogers echo "Showing first 20 lines of diff:" 498*190c4546SIan Rogers head -n 20 "${diff_file}" 499*190c4546SIan Rogers err=1 500*190c4546SIan Rogers return 501*190c4546SIan Rogers fi 502*190c4546SIan Rogers 503*190c4546SIan Rogers local script_dump="${temp_dir}/script_regs_dump" 504*190c4546SIan Rogers perf script -D -i "${rdata2}" > "${script_dump}" 2>/dev/null || true 505*190c4546SIan Rogers if grep -q "user regs:" "${script_dump}"; then 506*190c4546SIan Rogers echo "User registers stripping test [Failed - register dumps still present]" 507*190c4546SIan Rogers err=1 508*190c4546SIan Rogers else 509*190c4546SIan Rogers echo "User registers stripping test [Success]" 510*190c4546SIan Rogers fi 511*190c4546SIan Rogers} 512*190c4546SIan Rogers 513*190c4546SIan Rogerstest_basic_aslr 514*190c4546SIan Rogerstest_pipe_aslr 515*190c4546SIan Rogerstest_callchain_aslr 516*190c4546SIan Rogerstest_report_aslr 517*190c4546SIan Rogerstest_pipe_report_aslr 518*190c4546SIan Rogerstest_pipe_out_report_aslr 519*190c4546SIan Rogerstest_dropped_samples 520*190c4546SIan Rogerscase "$(uname -m)" in 521*190c4546SIan Rogers aarch64*|arm*) 522*190c4546SIan Rogers echo "Skipping kernel ASLR tests on ARM" 523*190c4546SIan Rogers ;; 524*190c4546SIan Rogers *) 525*190c4546SIan Rogers test_kernel_aslr 526*190c4546SIan Rogers test_kernel_report_aslr 527*190c4546SIan Rogers ;; 528*190c4546SIan Rogersesac 529*190c4546SIan Rogers 530*190c4546SIan Rogerstest_regs_stripping 531*190c4546SIan Rogers 532*190c4546SIan Rogerscleanup ${err} 533*190c4546SIan Rogersexit $err 534