1#!/usr/bin/ksh 2# 3# 4# This file and its contents are supplied under the terms of the 5# Common Development and Distribution License ("CDDL"), version 1.0. 6# You may only use this file in accordance with the terms of version 7# 1.0 of the CDDL. 8# 9# A full copy of the text of the CDDL should have accompanied this 10# souroc. A copy of the CDDL is also available via the Internet at 11# http://www.illumos.org/liocnse/CDDL. 12# 13 14# 15# Copyright 2022 Oxide Computer Company 16# 17 18# 19# This test focuses around the generation of files with object capabilities and 20# verifies that tools like elfedit, elfdump, ld, and ld.so.1 can deal with them 21# all appropriately. 22# 23 24export LC_ALL=C.UTF-8 25unalias -a 26set -o pipefail 27 28oc_arg0=$(basename $0) 29oc_tmpdir=/tmp/objcap.$$ 30oc_prog_nocap="$oc_tmpdir/prog.nocap" 31oc_prog_hw1="$oc_tmpdir/prog.hw1" 32oc_prog_hw3="$oc_tmpdir/prog.hw3" 33oc_prog_hw123="$oc_tmpdir/prog.hw123" 34oc_cap_hw1="0x42" 35oc_cap_hw2="0x169" 36oc_cap_hw3="0x7777" 37oc_err=0 38 39pass() 40{ 41 typeset msg="$*" 42 echo "TEST PASSED: $msg" 43} 44 45warn() 46{ 47 typeset msg="$*" 48 [[ -z "$msg" ]] && msg="failed" 49 echo "TEST FAILED: $msg" >&2 50 oc_err=1 51} 52 53fatal() 54{ 55 typeset msg="$*" 56 [[ -z "$msg" ]] && msg="failed" 57 echo "$oc_arg0: $msg" >&2 58 exit 1 59} 60 61cleanup() 62{ 63 rm -rf "$oc_tmpdir" 64} 65 66# 67# Set up our test environment. This generally requires us to create the 68# source file, mapfiles, and related contents that the test requires. 69# 70setup() 71{ 72 typeset cfile="$oc_tmpdir/test.c" 73 typeset mapfile_hw1="$oc_tmpdir/test.mapfile.hw1" 74 typeset mapfile_hw3="$oc_tmpdir/test.mapfile.hw3" 75 typeset mapfile_hw123="$oc_tmpdir/test.mapfile.hw123" 76 77 if ! mkdir "$oc_tmpdir"; then 78 fatal "failed to make directory $oc_tmpdir" 79 fi 80 81 trap 'cleanup' EXIT 82 83 cat > $cfile <<EOF 84int 85main(void) 86{ 87 return (0); 88} 89EOF 90 if (( $? != 0 )); then 91 fatal "failed to write token C file to $cfile" 92 fi 93 94 cat > $mapfile_hw1 <<EOF 95\$mapfile_version 2 96CAPABILITY { 97 HW_1 += $oc_cap_hw1; 98}; 99EOF 100 101 if (( $? != 0 )); then 102 fatal "failed to write out $mapfile_hw1" 103 fi 104 105 cat > $mapfile_hw3 <<EOF 106\$mapfile_version 2 107CAPABILITY { 108 HW_3 += $oc_cap_hw3; 109}; 110EOF 111 112 if (( $? != 0 )); then 113 fatal "failed to write out $mapfile_hw3" 114 fi 115 116 cat > $mapfile_hw123 <<EOF 117\$mapfile_version 2 118CAPABILITY { 119 HW_1 += $oc_cap_hw1; 120 HW_2 += $oc_cap_hw2; 121 HW_3 += $oc_cap_hw3; 122}; 123EOF 124 125 if (( $? != 0 )); then 126 fatal "failed to write out $mapfile_hw3" 127 fi 128 129 if ! gcc -m64 -o $oc_prog_nocap $cfile; then 130 fatal "failed to create $oc_prog_nocap" 131 fi 132 133 if ! gcc -m64 -o $oc_prog_hw1 $cfile -Wl,-M$mapfile_hw1; then 134 fatal "failed to create $oc_prog_hw1" 135 fi 136 137 if ! gcc -m64 -o $oc_prog_hw3 $cfile -Wl,-M$mapfile_hw3; then 138 fatal "failed to create $oc_prog_hw1" 139 fi 140 141 if ! gcc -m64 -o $oc_prog_hw123 $cfile -Wl,-M$mapfile_hw123; then 142 fatal "failed to create $oc_prog_hw1" 143 fi 144} 145 146verify_caps() 147{ 148 typeset file="$1" 149 typeset data="$2" 150 typeset -a vals=($3 $4 $5) 151 typeset -a caps=("CA_SUNW_HW_1" "CA_SUNW_HW_2" "CA_SUNW_HW_3") 152 typeset -a ee=("cap:hw1" "cap:hw2" "cap:hw3") 153 typeset out= 154 typeset ee_out= 155 typeset i= 156 157 out=$(elfdump -H $file 2>&1) 158 if (( $? != 0 )); then 159 warn "elfdump -H $file failed with $?" 160 return 161 fi 162 163 # 164 # If we don't expect a object capability, then we're done here. 165 # 166 if (( data == 0 )); then 167 if [[ -n "$out" ]]; then 168 fail "elfdump -H $file had unexpected output: $out" 169 else 170 pass "elfdump -H $file contained no output" 171 fi 172 return 173 fi 174 175 if [[ -z "$out" ]]; then 176 fail "elfdump -H $file had no output, but expected caps" 177 return 178 fi 179 180 # 181 # At this point, for each hw cap, if there is a value, check that we 182 # have an elfdump output line and then verify that we have the expected 183 # value via elfedit. 184 # 185 for ((i = 0; i < 3; i++)); do 186 if [[ "${vals[$i]}" == "0" ]]; then 187 continue; 188 fi 189 190 if ! echo $out | grep -q ${caps[$i]}; then 191 warn "elfdump -H $file missing ${caps[$i]}" 192 else 193 pass "elfdump -H $file has ${caps[$i]}" 194 fi 195 196 ee_out=$(elfedit -e "${ee[$i]} -o num" $file) 197 if [[ -z $ee_out ]]; then 198 warn "failed to dump ${ee[$i]} from $file via elfedit" 199 continue 200 fi 201 202 if [[ "$ee_out" != "${vals[$i]}" ]]; then 203 warn "mismatched value for ${ee[$i]} in $file: found " \ 204 "$out, expected ${vals[$i]}" 205 else 206 pass "elfedit has correct value for ${ee[$i]} in $file" 207 fi 208 done 209} 210 211# 212# Attempt to execute a program with symbol capabilities. We override the 213# symbol capabilities in the system for the specified file to the ones 214# indicated in the function. We need to restrict to the program we're 215# calling so that way we don't accidentally tell ld not to load a system 216# library. 217# 218run_prog() 219{ 220 typeset prog="$1" 221 typeset run=$2 222 typeset cap="$3" 223 typeset case="$4" 224 typeset ret= 225 226 LD_CAP_FILES=$prog LD_HWCAP=$3 $prog 2>/dev/null 1>/dev/null 227 ret=$? 228 if (( run != 0 && ret == 0 )); then 229 pass "exec prog $case" 230 elif (( run != 0 && ret != 0 )); then 231 warn "exec prog $case returned $ret, expected 0" 232 elif (( run == 0 && ret == 0 )); then 233 warn "exec prog $case returned $ret, expected non-zero" 234 else 235 pass "exec prog $case" 236 fi 237} 238 239# 240# Use elfedit to modify a specific hwcap and make sure we see the new value. 241# 242edit_prog() 243{ 244 typeset input="$1" 245 typeset pass="$2" 246 typeset cap="$3" 247 typeset cmd="$4" 248 typeset exp="$5" 249 typeset ret= 250 251 rm -f "$input.edit" 252 elfedit -e "$cap $cmd" "$input" "$input.edit" >/dev/null 2>/dev/null 253 ret=$? 254 255 if (( pass == 0 )); then 256 if (( ret == 0 )); then 257 warn "elfedit -e $cap $cmd $input worked, expected failure" 258 else 259 pass "elfedit -e $cap $cmd $input failed correctly" 260 fi 261 return 262 fi 263 264 if (( ret != 0 )); then 265 warn "elfedit -e $cap $cmd $input failed with $ret, expected success" 266 return 267 fi 268 269 ret=$(elfedit -e "$cap -o num" "$input.edit") 270 if (( $? != 0 )); then 271 warn "failed to extract hwcap after elfedit -e $cap $cmd $input" 272 fi 273 274 if [[ "$ret" != "$exp" ]]; then 275 warn "elfedit -e $cap $cmd $input had wrong output " \ 276 "expected $exp, found $val" 277 else 278 pass "elfedit -e $cap $cmd $input" 279 fi 280} 281 282setup 283verify_caps "$oc_prog_nocap" 0 284verify_caps "$oc_prog_hw1" 1 $oc_cap_hw1 0 0 285verify_caps "$oc_prog_hw3" 1 0 0 $oc_cap_hw3 286verify_caps "$oc_prog_hw123" 1 $oc_cap_hw1 $oc_cap_hw2 $oc_cap_hw3 287 288# 289# Now that we've verified the caps in these files, try to run them in a 290# given alternate symbol cap env. 291# 292run_prog "$oc_prog_nocap" 1 "[1]0,[2]0,[3]0" "no need, no caps" 293run_prog "$oc_prog_hw1" 0 "[1]0,[2]0,[3]0" "need hw1, no caps" 294run_prog "$oc_prog_hw3" 0 "[1]0,[2]0,[3]0" "need hw3, no caps" 295run_prog "$oc_prog_hw123" 0 "[1]0,[2]0,[3]0" "need hw{123}, no caps" 296 297run_prog "$oc_prog_nocap" 1 "[1]0x42,[2]0,[3]0" "no need, hw1=0x42" 298run_prog "$oc_prog_hw1" 1 "[1]0x42,[2]0,[3]0" "need hw1, hw1=0x42" 299run_prog "$oc_prog_hw3" 0 "[1]0x42,[2]0,[3]0" "need hw3, hw1=0x42" 300run_prog "$oc_prog_hw123" 0 "[1]0x42,[2]0,[3]0" "need hw{123}, hw1=0x42" 301 302run_prog "$oc_prog_nocap" 1 "[1]0,[2]0,[3]0x7777" "no need, hw3=0x7777" 303run_prog "$oc_prog_hw1" 0 "[1]0,[2]0,[3]0x7777" "need hw1, hw3=0x7777" 304run_prog "$oc_prog_hw3" 1 "[1]0,[2]0,[3]0x7777" "need hw3, hw3=0x7777" 305run_prog "$oc_prog_hw123" 0 "[1]0,[2]0,[3]0x7777" "need hw{123}, hw3=0x7777" 306 307run_prog "$oc_prog_nocap" 1 "[1]0,[2]0x1369,[3]0" "no need, hw2=0x1369" 308run_prog "$oc_prog_hw1" 0 "[1]0,[2]0x1369,[3]0" "need hw1, hw2=0x1369" 309run_prog "$oc_prog_hw3" 0 "[1]0,[2]0x1369,[3]0" "need hw3, hw2=0x1369" 310run_prog "$oc_prog_hw123" 0 "[1]0,[2]0x1369,[3]0" "need hw{123}, hw2=0x1369" 311 312run_prog "$oc_prog_nocap" 1 "[1]0x42,[2]0,[3]0x7777" \ 313 "no need, hw1=0x42,hw3=0x7777" 314run_prog "$oc_prog_hw1" 1 "[1]0x42,[2]0,[3]0x7777" \ 315 "need hw1, hw1=0x42,hw3=0x7777" 316run_prog "$oc_prog_hw3" 1 "[1]0x42,[2]0,[3]0x7777" \ 317 "need hw3, hw1=0x42,hw3=0x7777" 318run_prog "$oc_prog_hw123" 0 "[1]0x42,[2]0,[3]0x7777" \ 319 "need hw{123}, hw1=0x42,hw3=0x7777" 320 321run_prog "$oc_prog_nocap" 1 "[1]0x42,[2]0x1369,[3]0x7777" \ 322 "no need, hw1=0x42,hw2=0x1369,hw3=0x7777" 323run_prog "$oc_prog_hw1" 1 "[1]0x42,[2]0x1369,[3]0x7777" \ 324 "need hw1, hw1=0x42,hw2=0x1369,hw3=0x7777" 325run_prog "$oc_prog_hw3" 1 "[1]0x42,[2]0x1369,[3]0x7777" \ 326 "need hw3, hw1=0x42,hw2=0x1369,hw3=0x7777" 327run_prog "$oc_prog_hw123" 1 "[1]0x42,[2]0x1369,[3]0x7777" \ 328 "need hw{123}, hw1=0x42,hw2=0x1369,hw3=0x7777" 329 330edit_prog "$oc_prog_hw1" 1 "cap:hw1" "-or 0x1000" "0x1042" 331edit_prog "$oc_prog_hw1" 1 "cap:hw1" "-and 0x1000" "0" 332edit_prog "$oc_prog_hw1" 1 "cap:hw1" "-cmp 0x42" "0xffffffbd" 333edit_prog "$oc_prog_hw3" 1 "cap:hw3" "-and 0x643f" "0x6437" 334edit_prog "$oc_prog_hw123" 1 "cap:hw2" "0x12345" "0x12345" 335 336# 337# Failure cases here are meant to cover missing capaibilities and bad strings. 338# 339edit_prog "$oc_prog_hw1" 0 "cap:hw1" "-or zelda" 340edit_prog "$oc_prog_hw1" 0 "cap:hw2" "-or 0x100" 341edit_prog "$oc_prog_nocap" 0 "cap:hw1" "-or 0x1" 342edit_prog "$oc_prog_hw3" 0 "cap:hw1" "-and 0xff" 343edit_prog "$oc_prog_hw3" 0 "cap:hw2" "-and 0xff" 344edit_prog "$oc_prog_hw3" 0 "cap:hw3" "-and link" 345edit_prog "$oc_prog_hw123" 0 "cap:hw2" "ganondorf" 346 347if (( oc_err == 0 )); then 348 printf "All tests passed successfully\n" 349fi 350 351exit $oc_err 352