1#!/bin/sh 2# ASR live update script by David van Moolenbroek <david@minix3.org> 3 4# The path to the initial, standard system service binaries. 5SERVICE_PATH=/service 6 7# The path to the alternative, ASR-rerandomized system service binaries. 8# The path used here is typically a symlink into /usr for size reasons. 9# As of writing, the only way to create these sets of binaries is by means 10# of the host-side "minix/llvm/clientctl buildasr" command. 11SERVICE_ASR_PATH=$SERVICE_PATH/asr 12 13# A space-separated list of labels not to update in any case. The list 14# includes the memory service, which is currently not compiled with bitcode 15# and therefore also not instrumented. It also contains the VM service, 16# for which ASR is possible but too dangerous: much of its address space is 17# deliberately ignored by the instrumentation, and ASR would invalidate any 18# pointers from the ignored memory to the relocated memory. Note that 19# skipped services may still have rerandomized binaries on disk. 20SKIP="memory vm" 21 22# Custom live update states to use for certain label prefixes. This list is 23# made up of space-separated tokens, each token consisting of a label prefix, 24# followed by a colon, followed by the state number to use for those labels. 25# Currently it contains all services that make use of worker threads. This 26# setting should not need to exist; see the corresponding TODO item below. 27STATES="vfs:2 ahci_:2 virtio_blk_:2" 28 29# If this variable is set, it is used as timeout for the live updates. The 30# service(8) argument takes a number of click ticks, or a number of seconds 31# if the value ends with "HZ". 32TIMEOUT=300HZ 33 34# Configuration ends here. 35 36debug() { 37 if [ $verbose -eq 1 ]; then 38 echo "$@" 39 fi 40} 41 42verbose=0 43ret=0 44 45while getopts 'v' opt; do 46 case $opt in 47 v) verbose=1 48 ;; 49 ?) echo "Usage: $0 [-v] [label [label..]]" >&2 50 exit 1 51 esac 52done 53shift $(($OPTIND - 1)) 54 55if [ $# -eq 0 ]; then 56 services=$(echo /proc/service/*) 57else 58 services="$@" 59fi 60 61for service in $services; do 62 label=$(basename $service) 63 filename=$(grep filename: $service | cut -d' ' -f2) 64 count=$(grep ASRcount: $service | cut -d' ' -f2) 65 66 # Start by making sure we are not supposed to skip this service. 67 if echo " $SKIP " | grep -q " $label "; then 68 debug "skipping $label: found in skip list" 69 continue 70 fi 71 72 # The base binary of the program has number 0 and must be present. 73 if [ ! -f $SERVICE_PATH/$filename ]; then 74 debug "skipping $label: no base binary found" 75 continue 76 fi 77 78 # Count the ASR binaries for this program, starting from number 1. 79 # There must be at least one, so that we can switch between versions. 80 # By counting using a number rather than using a directory iterator, 81 # we avoid potential problems with gaps between the numbers by 82 # stopping at the first number for which no binary is present. 83 total=1 84 while [ -f $SERVICE_ASR_PATH/$total/$filename ]; do 85 total=$(($total + 1)) 86 done 87 88 if [ $total -eq 1 ]; then 89 debug "skipping $label: no ASR binaries found" 90 continue 91 fi 92 93 # Determine the path name of the binary to use for this update. 94 # TODO: pick the next binary at random rather than round-robin. 95 count=$((($count + 1) % $total)) 96 if [ $count -eq 0 ]; then 97 binary=$SERVICE_PATH/$filename 98 else 99 binary=$SERVICE_ASR_PATH/$count/$filename 100 fi 101 102 # Check whether the live update should use a state other than the 103 # default (namely state 1, which is "work free"). In particular, any 104 # programs that use threads typically need another state (namely state 105 # 2, which is "request free". TODO: allow services to specify their 106 # own default state, thus avoiding the redundancy introduced here. 107 state= 108 for token in $STATES; do 109 prefix=$(echo $token | cut -d: -f1) 110 if echo "$label" | grep -q -e "^$prefix"; then 111 state="-state $(echo $token | cut -d: -f2)" 112 fi 113 done 114 115 # Apply a custom timeout if present. This may be necessary in VMs. 116 maxtime= 117 if [ -n "$TIMEOUT" ]; then 118 maxtime="-maxtime $TIMEOUT" 119 fi 120 121 # Perform the live update. The update may legitimately fail if the 122 # service is not in the right state. TODO: report transient errors 123 # as debugging output only. 124 service -a update $binary -label $label -asr-count $count \ 125 $state $maxtime 126 error=$? 127 if [ $error -eq 0 ]; then 128 debug "updated $label to number $count, total $total" 129 else 130 echo "failed updating $label: error $error" >&2 131 ret=1 132 fi 133done 134 135exit $ret 136