Description: Security fix for the oarsh command Patches the oarsh script and oar.conf configuration file to remove a vulnerability which could allow a root exploit. Author: pierre.neyron@free.fr Origin: upstream --- This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ Index: oar/sources/core/tools/oar.conf.in =================================================================== --- oar.orig/sources/core/tools/oar.conf.in +++ oar/sources/core/tools/oar.conf.in @@ -532,20 +532,46 @@ CPUSET_PATH="/oar" # OARSH # ############################################################################### # -# This variable must be set to enable the use of oarsh from a frontale node -# Otherwise you must not set this variable if you are not on a frontale +# The following variable must be set to enable the use of oarsh on frontend +# machines. On other machines (compute nodes), it does not need to be set. OARSH_OARSTAT_CMD="%%BINDIR%%/oarstat" -# The following variable adds options to ssh (or OPENSSH_CMD if configured). -# If one option is not handled by your ssh version just remove it BUT be -# careful because these options are there for security reasons -OARSH_OPENSSH_DEFAULT_OPTIONS="-oProxyCommand=none -oPermitLocalCommand=no" +# The following variable gives the OpenSSH options which the oarsh command must +# understand in order to parse user commands. +# The value of OPENSSH_OPTSTR must match the option string of OpenSSH ssh +# command installed on the system (mind checking it is up-to-date, as OpenSSH +# development is very active), which can be found in the ssh.c file of the +# OpenSSH sources. For instance, the following command extracts the option +# string of OpenSSH 7.2p2 : +# +# $ cd path/to/openssh/sources/ +# $ grep getopt -A1 ssh.c | sed 's/.*"\(.\+\)".*/\1/' | xargs | sed 's/ //g' +# 1246ab:c:e:fgi:kl:m:no:p:qstvxACD:E:F:GI:KL:MNO:PQ:R:S:TVw:W:XYy +# +OPENSSH_OPTSTR="1246ab:c:e:fgi:kl:m:no:p:qstvxACD:E:F:GI:KL:MNO:PQ:R:S:TVw:W:XYy" + +# The following variable sets the OpenSSH options which oarsh actually uses. +# Any option which is filtered out from the OPENSSH_OPTSTR variable above is +# just ignored (see oarsh -v for debug) +# WARNING: if not fitlered out, some options may allow root exploit using oarsh. +# At least the following OpenSSH options are recommanded to be fitlered out: +# -a -A -i -l -o -p -E -F -G -I -w +# For more information, see: http://oar.imag.fr/wiki:security_tips +OPENSSH_OPTSTR_FILTERED="1246b:c:e:fgkm:nqstvxCD:KL:MNO:PQ:R:S:TVW:XYy" + +# The following variable forces OpenSSH configuration options for the ssh call +# made by in oarsh, so that, for security reasons, they cannot be set by the +# user (whenever "o:" is not filtered out in the OPENSSH_OPTSTR_FILTERED +# variable above). +# WARNING: for security, do not change unless you know what you are doing +OARSH_OPENSSH_DEFAULT_OPTIONS="-oProxyCommand=none -oPermitLocalCommand=no -oUserKnownHostsFile=%%OARHOMEDIR%%/.ssh/known_hosts" -# If you set this variable to something different from 0 then oarsh will act -# like a normal ssh **without** CPUSET restriction. -# WARNING: this is a critical functionality (this is only useful if users want -# to have a command to connect on every nodes without taking care of there ssh -# configuration and act like a ssh) +# If the following variable is set to a value which is not 0, oarsh will act +# like a normal ssh, **without** the CPUSET isolation mechanism. +# WARNING: this disable a critical functionality +# This can however be useful and different from simply using ssh, as it +# provides users with a mechanism which allows to connect to compute nodes +# without having to care of their ssh configuration (e.g. key setup) #OARSH_BYPASS_WHOLE_SECURITY="0" ############################################################################### Index: oar/sources/core/tools/oarsh/oarsh.in =================================================================== --- oar.orig/sources/core/tools/oarsh/oarsh.in +++ oar/sources/core/tools/oarsh/oarsh.in @@ -14,7 +14,11 @@ umask 0022 OARSH_OARSTAT_CMD= OPENSSH_CMD=/usr/bin/ssh -OARSH_OPENSSH_DEFAULT_OPTIONS="-oProxyCommand=none -oPermitLocalCommand=no" +OPENSSH_OPTSTR="1246ab:c:e:fgi:kl:m:no:p:qstvxACD:E:F:I:KL:MNO:PQ:R:S:TVw:W:XYy" +# Filtered out OpenSSH options: -a -A -i -l -o -p -E -F -I -w +OPENSSH_OPTSTR_FILTERED="1246b:c:e:fgkm:nqstvxCD:KL:MNO:PQ:R:S:TVW:XYy" +# Forced OpenSSH configuration options +OARSH_OPENSSH_DEFAULT_OPTIONS="-oProxyCommand=none -oPermitLocalCommand=no -oUserKnownHostsFile=%%OARHOMEDIR%%/.ssh/known_hosts" CPUSET_PATH= # If you set this variable to something different from 0 then oarsh will act @@ -22,7 +26,105 @@ CPUSET_PATH= OARSH_BYPASS_WHOLE_SECURITY="0" ############################################################################### -source "$OARCONFFILE" || exit 2 +# Source OAR config file, allowing the administrator to overwrite variables +. "$OARCONFFILE" || exit 2 + +# Parse OpenSSH options +# OPENSSH_OPTSTR can be extracted from the ssh.c file of OpenSSH sources +unset OARSH_DEBUG +parse_opts() { + OPTIND= + while getopts ":$OPENSSH_OPTSTR" OPT; do + if [ "$OPT" == "v" ]; then + OARSH_DEBUG=1 + fi + if [ "$OPT" == "i" ]; then + OAR_JOB_KEY_FILE=$OPTARG + fi + unset OPTFOUND + for ((i=0;i<${#OPENSSH_OPTSTR};i++)); do + if [ "x${OPENSSH_OPTSTR:$((i+1)):1}" == "x:" ]; then + if [ "$OPT" == "${OPENSSH_OPTSTR:$((i++)):1}" ]; then + OARSH_OPT[$OARSH_OPTCOUNT]=$OPT + OARSH_OPTARG[$((OARSH_OPTCOUNT++))]=$OPTARG + OPTFOUND=1 + fi + else + if [ "$OPT" == "${OPENSSH_OPTSTR:$i:1}" ]; then + OARSH_OPT[OARSH_OPTCOUNT]=$OPT + OARSH_OPTARG[$((OARSH_OPTCOUNT++))]="" + OPTFOUND=1 + fi + fi + [ -n "$OPTFOUND" ] && break + done + [ -n "$OPTFOUND" ] && continue + echo "oarsh: unknown option -$OPTARG" 1>&2 + exit 7 + done +} + +# Parse command line in the OpenSSH form +# Expected syntax: "oarsh [opts] [user@] [opts] [command]" +unset OARSH_OPT +unset OARSH_OPTARG +OARSH_ERROR=0 +OARSH_OPTCOUNT=0 +parse_opts "$@" +shift $((OPTIND-1)) +OARSH_HOST="${1##*@}" +if [ -z "$OARSH_HOST" ]; then + echo "oarsh: cannot retrieve host" + exit 7 +fi +OARSH_USER="${1/%$OARSH_HOST/}" +OARSH_USER="${OARSH_USER%@}" +shift 1 +parse_opts "$@" +shift $((OPTIND-1)) +REMOTE_CMD="$@" + +# Debug output +if [ -n "$OARSH_DEBUG" ]; then + for ((i=0; i < $OARSH_OPTCOUNT; i++)); do + echo "debug oarsh: OARSH_OPT[$i]=-${OARSH_OPT[$i]}${OARSH_OPTARG[$i]}" 1>&2 + done + cat 1>&2 <&2 + fi +done + +# Debug output +if [ -n "$OARSH_DEBUG" ]; then + echo "debug oarsh: OPT=${OPT[@]}" 1>&2 +fi # Add security option for X11 forwarding XAUTH_LOCATION="%%XAUTHCMDPATH%%" @@ -55,15 +157,15 @@ fi # (oarsh acts like a ssh and can connect on every nodes) if [ "$OARSH_BYPASS_WHOLE_SECURITY" != "0" ]; then export OAR_CPUSET="undef" - exec $OPENSSH_CMD $OARSH_OPENSSH_DEFAULT_OPTIONS -oSendEnv="OAR_CPUSET OAR_JOB_USER" "$@" - echo "oarsh: Failed to connect using cpuset environement" + exec $OPENSSH_CMD $OARSH_OPENSSH_DEFAULT_OPTIONS -oSendEnv="OAR_CPUSET OAR_JOB_USER" "${OPT[@]}" $OARSH_HOST -- "$REMOTE_CMD" + echo "oarsh: Failed to connect using cpuset environement" 1>&2 exit 5 fi # -1- try connection using a user provided job key file for a job using the job key mechanism if [ -n "$OAR_JOB_KEY_FILE" ] then - # first, get rid of remaining unused .Xautority.{pid} files if any... + # first, get rid of remaining unused jobkey files if any... for f in $OAR_RUNTIME_DIRECTORY/oarsh.jobkey.*; do [ -e "/proc/${f#$OAR_RUNTIME_DIRECTORY/oarsh.jobkey.}" ] || rm -f $f done @@ -79,8 +181,8 @@ then umask $TMPOLDUMASK umask $OLDUMASK - exec $OPENSSH_CMD $OARSH_OPENSSH_DEFAULT_OPTIONS -i $TMP_JOB_KEY_FILE "$@" - echo "oarsh: Failed to connect using the job key: $OAR_JOB_KEY_FILE" + exec $OPENSSH_CMD $OARSH_OPENSSH_DEFAULT_OPTIONS -i $TMP_JOB_KEY_FILE "${OPT[@]}" $OARSH_HOST -- "$REMOTE_CMD" + echo "oarsh: Failed to connect using the job key: $OAR_JOB_KEY_FILE" 1>&2 exit 3 fi @@ -90,27 +192,31 @@ fi TMP_JOB_KEY_FILE="$OAR_RUNTIME_DIRECTORY/$OARDO_USER.jobkey" if [ -r $TMP_JOB_KEY_FILE ]; then umask $OLDUMASK - exec $OPENSSH_CMD $OARSH_OPENSSH_DEFAULT_OPTIONS -i $TMP_JOB_KEY_FILE "$@" - echo "oarsh: Failed to connect using the cpuset job key: $TMP_JOB_KEY_FILE" + exec $OPENSSH_CMD $OARSH_OPENSSH_DEFAULT_OPTIONS -i $TMP_JOB_KEY_FILE "${OPT[@]}" $OARSH_HOST -- "$REMOTE_CMD" + echo "oarsh: Failed to connect using the cpuset job key: $TMP_JOB_KEY_FILE" 1>&2 exit 4 fi if [ "$CPUSET_PATH" != "" ]; then if [ -r /proc/self/cpuset ]; then - OAR_CPUSET=$(< /proc/self/cpuset) - if [ "${OAR_CPUSET%/*}" = "$CPUSET_PATH" ] || [ "${OAR_CPUSET%/*}" = "$CPUSET_PATH/" ]; then + if [ -n "$GET_CURRENT_CPUSET_CMD" ]; then + OAR_CPUSET=$(bash -c "$GET_CURRENT_CPUSET_CMD") + else + OAR_CPUSET=$(< /proc/self/cpuset) + fi + if [ "${OAR_CPUSET%/*}" == "$CPUSET_PATH" ] || [ "${OAR_CPUSET%/*}" == "$CPUSET_PATH/" ]; then JOB_KEY_FILE="$OAR_RUNTIME_DIRECTORY/${OAR_CPUSET##*/}.jobkey" if [ -r $JOB_KEY_FILE ]; then umask $OLDUMASK - exec $OPENSSH_CMD $OARSH_OPENSSH_DEFAULT_OPTIONS -i $JOB_KEY_FILE "$@" - echo "oarsh: Failed to connect using the cpuset job key: $JOB_KEY_FILE" + exec $OPENSSH_CMD $OARSH_OPENSSH_DEFAULT_OPTIONS -i $JOB_KEY_FILE "${OPT[@]}" $OARSH_HOST -- "$REMOTE_CMD" + echo "oarsh: Failed to connect using the cpuset job key: $JOB_KEY_FILE" 1>&2 exit 4 fi export OAR_CPUSET export OAR_JOB_USER=$OARDO_USER umask $OLDUMASK - exec $OPENSSH_CMD $OARSH_OPENSSH_DEFAULT_OPTIONS -oSendEnv="OAR_CPUSET OAR_JOB_USER" "$@" - echo "oarsh: Failed to connect using cpuset environement" + exec $OPENSSH_CMD $OARSH_OPENSSH_DEFAULT_OPTIONS -oSendEnv="OAR_CPUSET OAR_JOB_USER" "${OPT[@]}" $OARSH_HOST -- "$REMOTE_CMD" + echo "oarsh: Failed to connect using cpuset environement" 1>&2 exit 5 fi fi @@ -161,8 +267,8 @@ if [ -n "$OAR_JOB_ID" ]; then export OAR_CPUSET umask $OLDUMASK - exec $OPENSSH_CMD $OARSH_OPENSSH_DEFAULT_OPTIONS -oSendEnv="OAR_CPUSET OAR_JOB_USER" "$@" - echo "oarsh: Failed to connect using cpuset environement" + exec $OPENSSH_CMD $OARSH_OPENSSH_DEFAULT_OPTIONS -oSendEnv="OAR_CPUSET OAR_JOB_USER" "${OPT[@]}" $OARSH_HOST -- "$REMOTE_CMD" + echo "oarsh: Failed to connect using cpuset environement" 1>&2 exit 5 fi