Блокировка ввода в программах обработки журналов



Блокировка ввода в программах обработки журналов

Я уже говорил, что это упрощенная версия программы bigbuffy. С упрощением реализации, в особенности на различных платформах, связана неприятная особенность этой версии: во время сброса данных т диск она не может продолжать считывать ввод. Во время сброса буфера программе, посылающей свой вывод bigbuffy, операционная система может дать указание приостановить операции, пока не будет очищен ее буфер вывода. К счастью, сброс данных происходит быстро v. окно, в котором это может произойти, будет очень маленьким, но это все равно неприятно.

Вот два возможных решения этой проблемы:

  • Переписать bigbuffy, используя двойную буферизацию и многозадачность. Вместо одного буфера можно создать два. Во время получения сигнала программа будет записывать журнал во второй буфер до тех пор, пока дочерний процесс или другой поток обрабатывает сброс данных из первого буфера. При получении следующей сигнала буферы вновь меняются местами.
  • Переписать bigbuffy, чтобы разделить чтение и запись при сброс данных в файл. Самая простая версия этого подхода предполагает что несколько строк записываются в файл каждый раз после про чтения новой строки. Это может оказаться не простым делом, если журнал «разорван» и не поступает постоянным потоком. Вряд л! кому-то захочется ждать новую строку вывода для того, чтобы можно было сбросить буфер на диск. Так что придется использовать тайм-ауты или некий механизм внутренних часов, чтобы справиться с этой проблемой.

Оба этих подхода трудно реализовать так, чтобы они были преносимыми между различными платформами, отсюда и упрощенная версия; приведенная в книге.

Безопасность в программах, обрабатывающих журналы

Вы могли заметить, что в bigbuffy операциям открытия файлов вывода и записи в них уделяется внимания больше, чем обычно. Это пример защищенного (оборонительного) стиля программирования, о котором упоминалось уже в разделе «Ротация журналов». Если эта программа предназначена для отладки сервера, почти наверняка она будет запущена привилегированным пользователем. Очень важно продумать все ситуации, которые могут привести к тому, что программой кто-то злоупотребит.

Например, представьте ситуацию, когда файл, в который выводятся данные, был злонамеренно заменен ссылкой на другой файл. Если наивно открыть и записать данные в этот файл, можно обнаружить, что мы перезаписали какой-нибудь важный файл, например /etc/passwd. Даже если мы проверим файл вывода данных перед самым его открытием, злоумышленник может подменить его перед тем, как мы действительно начнем записывать в него данные. Во избежание таких неприятностей можно использовать такой сценарий:

  • Мы проверяем, существует ли файл, в который выводятся данные. Если да, мы выполняем lstat(), чтобы получить о нем информацию.
  • Открываем файл в режиме до записи.
  • Перед тем как собственно записать в него данные, мы выполняем lstat() для открытого файлового дескриптора и проверяем, тот же это файл, что мы ожидаем, или нет. Если это другой файл (т. е. кто-то заменил его ссылкой прямо перед открытием), мы не записываем в него данные и выводим соответствующее предупреждение. Этот шаг позволяет избежать состояния перехвата, о котором говорилось в главе 1.

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

Подобные «уловки» необходимы в большинстве Unix-систем, поскольку первоначально Unix создавался без особой заботы о безопасности. Брешь в безопасности, связанная с символическими ссылками, не является проблемой в NT4, т. к. они являются малоиспользуемой частью подсистемы POSIX, не проблема это и в MacOS, поскольку тут не существует понятия «привилегированный пользователь».



Содержание раздела