Книга: Программирование для Linux. Профессиональный подход

Листинг 10.6. (grep-dictionary.c) Поиск слова в словаре

Листинг 10.6. (grep-dictionary.c) Поиск слова в словаре

#include <stdio.h>
#include <stdlib.h>
/* Функция возвращает ненулевое значение, если аргумент WORD
   встречается в файле /usr/dict/words. */
int grep_for_word(const char* word) {
 size_t length;
 char* buffer;
 int exit_code;
 /* Формирование строки 'grep -x WORD /usr/dict/words'.
    Строка выделяется динамически во избежание
    переполнения буфера. */
 length =
  strlen("grep -х ") + strlen(word) +
 strlen(" /usr/dict/words") + 1;
 buffer = (char*)malloc(length);
 sprintf(buffer, "grep -x %s /usr/dict/words", word);
 /* Запуск команды. */
 exit_code = system(buffer);
 /* Очистка буфера. */
 free(buffer);
 /* Если команда grep вернула значение 0, значит, слово найдено
    в словаре. */
 return exit_code == 0;
}

Обратите внимание на подсчет числа символов в строке и динамическое выделение буфера, что позволяет обезопасить программу от переполнения буфера. К сожалению, небезопасна сама функция system() (описана в разделе 3.2.1, "Функция system()"). Функция вызывает стандартный интерпретатор команд и принимает от него код завершения. Но что произойдет, если злоумышленник вместо слова введет показанную ниже строку?

foo /dev/null; rm -rf /

В этом случае сервер выполнит такую команду:

grep -х foo /dev/null; rm -rf / /usr/dict/words

Теперь проблема стала очевидной. Пользователь запустил одну команду, якобы grep, а на самом деле их оказалось две, так как интерпретатор считает точку с запятой разделителем команд. Первая команда — это по-прежнему безобидный вызов утилиты grep, зато вторая команда пытается удалить все файлы в системе. Даже если серверная программа не имеет привилегий суперпользователя, она удалит все файлы, доступные запустившему ее пользователю. Похожая проблема возникает и при использовании функции popen() (описана в разделе 3.4.4, "Функции popen() и pclose()"), которая создает канал между родительским и дочерним процессами, но тоже вызывает интерпретатор для запуска команды.

Существуют два способа устранения подобных проблем. Первый заключается в использовании функции семейства exec() вместо функции system() или popen(). Специальные символы интерпретатора команд (например, точка с запятой) не подвергаются обработке, если они присутствуют в списке аргументов функции exec(). Естественно, при этом пропадают преимущества таких функций, как system() и popen().

Второй способ — проверка строки на предмет "благонадежности". В случае сервера словарей следует убедиться в том, что слово содержит только буквы (для этого предназначена функция isalpha()). Такое слово не представляет угрозы.

Оглавление книги


Генерация: 1.207. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз