Проблема полягає в тих випадках, коли вміст $xне був дезінфікований і містить дані, які потенційно можуть бути під контролем зловмисника у випадках, коли код оболонки може в кінцевому підсумку використовуватися в контексті ескалації привілеїв (наприклад, скрипт, на який посилається setuid додаток, скрипт sudoers або використовується для обробки даних, що виходять за межі мережі (CGI, DHCP гак ...) прямо чи опосередковано).
Якщо:
x='(PATH=2)'
Потім:
x=$((1-$x)))
має побічний ефект встановлення PATHна 2(відносний шлях, який цілком може бути під контролем нападника). Ви можете замінити PATHна LD_LIBRARY_PATHабо IFS... Те ж саме відбувається з x=$((1-x))bash, zsh або ksh (не тире чи yash, які приймають лише числові константи у змінних).
Зауважте, що:
x=$((1-$x))
не працюватимуть належним чином для від'ємних значень $xу деяких оболонках, які реалізують --оператор ( необов'язково відповідно до POSIX) (декремент) (як у випадку x=-1, це означає, що попросити оболонку оцінити 1--1арифметичний вираз). "$((1-x))"не має проблеми, оскільки xвона розширюється як частина (не раніше) арифметичної оцінки.
В bash, zshі ksh(ні dashабо yash), якщо xє:
x='a[0$(uname>&2)]'
Тоді розширення $((1-$x))або $((1-x))спричиняє виконання цієї unameкоманди (бо zsh, aповинно бути змінною масиву, але для цього можна використовувати, psvarнаприклад).
Таким чином, не слід використовувати неініцалізірованние або не продезінфікують зовнішні дані в арифметичних виразах в оболонках (зверніть увагу , що арифметична оцінка може бути зроблена шляхом $((...))(він же $[...]в bashабо zsh) , але і в залежності від оболонки в let, [/ test, declare/typeset/export..., return, break, continue, exit, printf, printвбудовані, індекси масиву ((..))та [[...]]конструкції, щоб назвати декілька).
Щоб перевірити, чи змінна містить буквальне десяткове ціле число, ви можете використовувати POSIXly:
case $var in
("" | - | *[!0123456789-]* | ?*-*) echo >&2 not a valid number; exit 1;;
esac
Будьте уважні, що [0-9]в деяких локальних збігах більше 0123456789. [[:digit:]]повинно бути гаразд, але я б не став на це.
Також пам’ятайте, що числа з провідними нулями в деяких контекстах розглядаються як восьмеричні ( 010іноді це 10, іноді 8), і будьте обережні, що перевірка вище дозволить пропустити цифри, які потенційно перевищують максимальне ціле число, що підтримується вашою системою (або будь-яке додаток, яке ви хочете використовувати це ціле число; bash, наприклад, розглядає 18446744073709551616 як 0, як це 2 64 ). Тому ви можете додати додаткові чеки у цій заяві вище, наприклад:
(0?* | -0?*)
echo >&2 'Only decimal numbers without leading 0 accepted'; exit 1;;
(-??????????* | [!-]?????????*)
echo >&2 'Only numbers from -999999999 to 999999999 supported'; exit 1;;
Приклади:
$ 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
Більше читання на:
x='P=3'; : $(($x + 5))буде встановленоPу 8, алеx='P=3'; : $((x + 5))встановитьсяPу3(вzsh,kshабоbash). "Те саме відбувається і з$((x + 1))..." зараз невірно; він буде встановленийPATHв2, як у давнину.