#!/bin/sh
#
# version 3.0 Sep 25 11:21:02 PDT 1998

# Protect SPARC stack against unwanted exec access
# Side effect: growth in data segment also loses exec bit.
#
# When run as /etc/rc2.d/S07*, all programs except init are protected.
#
# Made for 2.5, seems to work on 2.4
#
# The assembly checking may need tweaking depending on OS level and
# patchlevel.
#
# Casper Dik (Casper.Dik@Holland.Sun.COM)
#
#
PATH=/usr/bin:$PATH

#
# Set/get values using adb.
#
getvalue ()
{
    echo $1/$2 | adb -k /dev/ksyms /dev/mem | awk  "\"$1:\""' == $1 {print $2}'
}
setvalue ()
{
    echo $1/$2$3 | adb -wk /dev/ksyms /dev/mem >/dev/null 2>&1
}

#
# Check whether setting/unsetting is dangerous.
#

check ()
{
    map=`getvalue $mapaddr X`
    zfod=`getvalue $zfodaddr x`
    if [ "$map" = "$oldmap" -a "$zfod" = "$oldzfod" ]
    then
	old=true;
    else
	old=false
    fi
    if [ "$map" = "$newmap" -a "$zfod" = "$newzfod" ]
    then
	new=true
    else
	new=false
    fi
}


p=`basename $0`
mapaddr=map_hunk+8
zfodaddr=zfod_segvn_crargs+0xd

#
# Instruction should at $mapaddr should be: mov 0xf,%reg or mov 0xb,%reg
# this is a synthetic instruction that encodes as or %g0,0xf,$reg
# 10rr rrr0 0001 0000 0010 0000 0000 1x11
#
# Try and find it at sevel locations.
#
for mapaddr in map_hunk+8 map_hunk+0xc
do
    mapval=`getvalue $mapaddr X`
    case $mapval in
    ??10200f | ??10200b)
	reg=`expr $mapval : '\(..\)'`
	break;;
    esac
done
if [ -z "$reg" ]
then
    echo "${p}: Instruction doesn't match" 1>&2
    exit 1
fi

# In reality not all reg values are valid, only even values in the
# range 0x90 - 0xbe  
case "$reg" in
[9ab][02468ace]);;
*) echo "${p}: Instruction doesn't match" 1>&2; exit 1;;
esac

echo "${p}: Register prefix set to $reg ($mapval@$mapaddr)"

oldmap=${reg}10200f
newmap=${reg}10200b
oldzfod=f0f
newzfod=b0f

case "$1" in
start)
    check
    if $new
    then
	echo "${p}: New kernel parameters already set" 1>&2
	exit 0
    fi
    if $old
    then
	setvalue $mapaddr W $newmap
	setvalue $zfodaddr w $newzfod
	echo "${p}: Stack protected"
    else
	echo "${p}: Kernel value mismatch $map != $oldmap or $zfod != $oldzfod" 1>&2
	exit 1
    fi
    ;;
stop)
    check
    if $old
    then
	echo "${p}: Old kernel parameters already set" 1>&2
	exit 0
    fi
    if $new
    then
	setvalue $mapaddr W $oldmap
	setvalue $zfodaddr w $oldzfod
	echo "${p}: Stack no longer protected"
    else
	echo "${p}: Kernel value mismatch $map != $newmap or $zfod != $newzfod" 1>&2
	exit 1
    fi
    ;;
esac

