Может ли запуск bash-скрипта с помощью sh быть потенциально опасным?

Вопрос или проблема

Очевидно, что когда вы запускаете Bash-скрипт с помощью sh (например, sh ./path/to/bash-script.sh), вы можете столкнуться с ошибками в случаях, когда sh является символической ссылкой на не-Bash оболочку, которая не поддерживает функцию, используемую в скрипте.

Мне любопытно, может ли быть случай, когда скрипт, предназначенный для Bash, выполняемый с помощью dash или какой-либо базовой POSIX оболочки, приведет к выполнению кода, который в противном случае определенно не был бы выполнен.

Все, что я тестировал (например, группировка команд (( ... ))), просто заставляет скрипт завершаться преждевременно при выполнении с помощью примитивной POSIX оболочки, не вызывая никакого потенциального ущерба.

У меня нет ответа, который вы ищете, и я уверен, что кто-то может предложить несколько действительно интересных примеров, но ответ на ваш вопрос однозначно “да”.

Как вы упоминаете, запуск bash-скрипта с помощью posix оболочки, вероятно, приведет к нескольким ошибкам, которые заставят код выполняться всевозможными неожиданными способами, и это может быть очень опасно. Существует практически бесконечное количество способов, как выполнение else из-за неожиданной ошибки, когда вы должны были выполнить if, может считаться “опасным” для производственной инфраструктуры.

Простой пример:

$ cat shtest.sh
#!/usr/bin/env bash

if [[ a == a ]]; then
    echo bash
else
    echo dash
fi
$ ./shtest.sh
bash
$ dash ./shtest.sh
./shtest.sh: 3: [[: not found
dash

Конечно, вы получите ошибку, но код в части else все равно выполнится. А что если это будет:

if [[ $server == in_use ]]; then
    do_thing
else
    delete_server
fi

Я думаю, что что-то, что вы ищете, это команды, которые не вызывают ошибок, например, расширение фигурных скобок.

Например, если у вас есть скрипт, который проверяет состояние lb_{1..3}, вы можете сказать, что если один из них не работает, запустите другой lb-сервер. При выполнении с помощью dash он интерпретирует lb_{1..3} как буквальную строку вместо lb_1, lb_2, lb_3 и потенциально создаст сотни ненужных замен.

Все, что я тестировал (например, группировка команд (( ... )))), просто заставляет скрипт завершаться преждевременно…

Синтаксис ((...)) предназначен для арифметических выражений, а не для группировки команд.

Я не думаю, что такие ошибки обязательно заставят скрипт завершиться преждевременно. Это зависит от того, считается ли выражение синтаксической ошибкой (что приведет к завершению оболочки) или просто интерпретируется как недопустимая команда. Рассмотрим что-то вроде этого:

MYVAR=3

if (( MYVAR > 2 )); then
  echo "Выполнить действие 1"
else
  echo "Выполнить действие 2"
fi

Если я запущу этот скрипт с помощью bash, мы увидим:

$ bash example.sh
Выполнить действие 1

Но если я запущу скрипт с использованием не-Bash оболочки, такой как dash, мы увидим:

$ dash example.sh
example.sh: 3: MYVAR: не найден
Выполнить действие 2

Наша попытка использовать функцию, специфичную для bash, терпит неудачу, но не вызывает выхода оболочки; она просто продолжает и выполняет действие, отличное от ожидаемого (в данном случае это потому, что dash рассматривает ((...)) как оператор вложенной подсистемы, поэтому он пытается выполнить MYVAR как команду). Кроме того, выражение MYVAR > 2 будет интерпретироваться как перенаправление ввода-вывода оболочки, так что оно создаст или перезапишет файл с именем 2.

Это “опасно”? Не уверен, но это определенно может привести к неожиданному поведению.


Второй пример: рассмотрите вот такой скрипт:

shopt -s nullglob

for x in *foo; do
  echo "$x"
done

Команда shopt специфична для bash. Запуск этого в bash (предположим, что у вас нет файлов, соответствующих шаблону в вашей текущей директории) не приведет к выводу.

Запуск этого с помощью dash приведет к:

example.sh: 1: shopt: не найден
*foo

Если вы использовали результат этого выражения для создания файлов, это могло бы привести к тому, что dash создаст недопустимые файлы и снова может вызвать неожиданное поведение в скрипте.

Ответ или решение

Запуск Bash-скрипта с использованием sh действительно может представлять собой потенциальную опасность, особенно если sh ссылается на оболочку, не поддерживающую все конструкции и возможности, доступные в Bash. Это может привести к неожиданному поведению скриптов, что может вызвать множество проблем, включая утечку данных, потерю информации и даже возможность взлома системы.

Проблемы совместимости

Когда вы запускаете скрипт, созданный для Bash, через другую оболочку, например, dash, некоторые команды могут не выполняться из-за отсутствия поддержки соответствующих синтаксических конструкций. Простые элементы, такие как условные конструкции if, могут привести к разному поведению, если они используют синтаксис, присущий только Bash. Например, использование двойных квадратных скобок [[...]] для проверки условий не будет поддерживаться в dash, что приведёт к ошибкам.

#!/usr/bin/env bash
if [[ a == a ]]; then
    echo "bash"
else
    echo "dash"
fi

Запуск этого кода с dash приведёт к ошибке:

./shtest.sh: 3: [[: not found

Однако, скрипт всё равно продолжит выполнение, что откроет путь для потенциально небезопасного выполнения кода в блоке else.

Непредсказуемое поведение

При использовании оболочки, которая не поддерживает все функции Bash, ошибки могут приводить к выполнению нежелательного кода. Например:

if [[ $server == in_use ]]; then
    do_thing
else
    delete_server
fi

Если условие [[...]] не будет распознано, и скрипт перейдёт к выполнению блока else, это может иметь серьезные последствия, если delete_server выполняет разрушительные действия.

Условные выражения и перенаправление

Ваша логика может также ошибочно выполниться, если вместо ожидаемого поведения будет интерпретировано неверное. Например, конструкция ((...)), предназначенная для арифметики в Bash, может быть распознана dash как команда, что также приведет к неожиданным результатам:

MYVAR=3
if (( MYVAR > 2 )); then
    echo "Do thing 1"
else
    echo "Do thing 2"
fi

В dash эта конструкция вызовет ошибку, но затем скрипт продолжит выполнение, что может привести к попытке выполнения неправильной логики с неожиданным результатом.

Глобальные параметры и шапка shopt

Еще один пример, который стоит рассмотреть, это использование команды shopt -s nullglob:

shopt -s nullglob
for x in *foo; do
    echo "$x"
done

Эта команда не распознается в dash, и вместо того, чтобы ничего не выводить (что правильно для Bash), она напечатает *foo, что может создать ошибки в следующем коде, если он зависит от переменной x.

Заключение

Запуск скриптов Bash с использованием sh может привести к опасным багам и подрыву безопасности системы из-за выполнения неожиданного кода. Рекомендуется всегда использовать оболочку, соответствующую синтаксису и возможностям скрипта, чтобы избежать ошибок, которые могут быть неочевидными на первый взгляд. Всегда тестируйте ваши скрипты в целевой среде, чтобы гарантировать, что они работают как задумано, и избегайте взаимодействия с чувствительными данными в тестовее.

Оцените материал
Добавить комментарий

Капча загружается...