Il problema si verifica nei casi in cui il contenuto di $xnon è stato disinfettato e contiene dati che potrebbero essere potenzialmente sotto il controllo di un utente malintenzionato nel caso in cui il codice shell possa finire per essere utilizzato in un contesto di escalation di privilegi (ad esempio uno script invocato da un setuid applicazione, uno script sudoers o utilizzato per elaborare dati fuori rete (CGI, hook DHCP ...) direttamente o indirettamente).
Se:
x='(PATH=2)'
Poi:
x=$((1-$x)))
ha l'effetto collaterale dell'impostazione PATHsu 2(un percorso relativo che potrebbe benissimo essere sotto il controllo dell'attaccante). Puoi sostituirlo PATHcon LD_LIBRARY_PATHo IFS... Lo stesso succede con x=$((1-x))bash, zsh o ksh (non trattino né yash che accettano solo costanti numeriche nelle variabili lì).
Nota che:
x=$((1-$x))
non funzionerà correttamente per valori negativi $xin alcune shell che implementano l' --operatore ( opzionale secondo POSIX) (decremento) (come con x=-1, ciò significa chiedere alla shell di valutare l' 1--1espressione aritmetica). "$((1-x))"non ha il problema poiché xviene espanso come parte della valutazione aritmetica (non prima).
In bash, zshe ksh(no dasho yash), se xè:
x='a[0$(uname>&2)]'
Quindi l'espansione $((1-$x))o $((1-x))causa l' unameesecuzione di quel comando (per zsh, adeve essere una variabile array, ma si può usare psvarper esempio per quello).
In sintesi, non si dovrebbe usare non inizializzate o non sterilizzate dati esterni in espressioni aritmetiche in gusci (si noti che la valutazione aritmetica può essere fatto da $((...))(aka $[...]in basho zsh), ma anche a seconda della shell in let, [/ test, declare/typeset/export..., return, break, continue, exit, printf, printbuiltin, indici di array ((..))e [[...]]costrutti per citarne alcuni).
Per verificare che una variabile contenga un numero intero decimale letterale, è possibile utilizzare POSIXly:
case $var in
("" | - | *[!0123456789-]* | ?*-*) echo >&2 not a valid number; exit 1;;
esac
Attenzione che [0-9]in alcune versioni locali più di 0123456789. [[:digit:]]dovrebbe essere OK ma non ci scommetterei.
Ricorda inoltre che i numeri con zeri iniziali sono trattati come ottali in alcuni contesti (a 010volte 10, a volte 8) e fai attenzione che il controllo sopra consentirà di passare attraverso numeri potenzialmente più grandi dell'intero massimo supportato dal tuo sistema (o qualunque applicazione tu voglia usa quel numero intero in; bash ad esempio considera 18446744073709551616 come 0 dato che è 2 64 ). Quindi potresti voler aggiungere ulteriori controlli nell'affermazione del caso sopra come:
(0?* | -0?*)
echo >&2 'Only decimal numbers without leading 0 accepted'; exit 1;;
(-??????????* | [!-]?????????*)
echo >&2 'Only numbers from -999999999 to 999999999 supported'; exit 1;;
Esempi:
$ export 'x=psvar[0$(uname>&2)]'
$ ksh93 -c 'echo "$((x))"'
Linux
ksh93: psvar: parameter not set
$ ksh93 -c '[ x -lt 2 ]'
Linux
ksh93: [: psvar: parameter not set
$ bash -c 'echo "$((x))"'
Linux
0
$ bash -c '[[ $x -lt 2 ]]'
Linux
$ bash -c 'typeset -i a; export a="$x"'
Linux
$ bash -c 'typeset -a a=([x]=1)'
Linux
$ bash -c '[ -v "$x" ]'
Linux
$ mksh -c '[[ $x -lt 2 ]]'
Linux
$ zsh -c 'echo "$((x))"'
Linux
0
$ zsh -c 'printf %d $x'
Linux
0
$ zsh -c 'integer x'
Linux
$ zsh -c 'exit $x'
Linux
Altre letture a:
x='P=3'; : $(($x + 5))sarà impostatoPsu 8, max='P=3'; : $((x + 5))sarà impostatoPsu3(inzsh,kshobash). "Lo stesso accade con$((x + 1))..." non è corretto ora; sarà impostatoPATHsu2, come un tempo.