Повреждение файлового дескриптора SVN

Я просматривал исходный код SVN и нашел этот комментарий в исходном коде.

/* The following makes sure that file descriptors 0 (stdin), 1
   (stdout) and 2 (stderr) will not be "reused", because if
   e.g. file descriptor 2 would be reused when opening a file, a
   write to stderr would write to that file and most likely
   corrupt it. */

за которым следует этот код:

if ((fstat(0, &st) == -1 && open("/dev/null", O_RDONLY) == -1) ||
    (fstat(1, &st) == -1 && open("/dev/null", O_WRONLY) == -1) ||
    (fstat(2, &st) == -1 && open("/dev/null", O_WRONLY) == -1))
  {
    if (error_stream)
      fprintf(error_stream, "%s: error: cannot open '/dev/null'\n",
              progname);
    return EXIT_FAILURE;
  }

Я не понимаю, как «повторное использование» дескриптора файла может повредить файл. И как вы можете открыть файл с файловым дескриптором 2 (stderr)? И как открытие файла может повлиять на запись в stderr?

Если код записывает сообщение об ошибке в стандартную ошибку, но стандартная ошибка указывает на файл SVN, а не на терминал или что-то подобное, то этот файл SVN будет поврежден.

Jonathan Leffler 25.01.2023 23:20

@JonathanLeffler Я не понимаю, как стандартная ошибка может указывать на файл SVN. Разве мы не используем его в качестве дескриптора выходного файла. Если мы, например. иметь файловый дескриптор, открытый для файла, такого как fopen, и возвращать FP, как этот FP указывает на stderr. Есть ли код, который может продемонстрировать это?

Zer0day 25.01.2023 23:29

@Plimpus Да, я искал там свою локальную копию репозитория svn. Дело в том, что я не понимаю, как указатель файла может указывать на stderr. Например, это проблема, когда мы fprintf выводим на экран, что unix каким-то образом неправильно понимает fprintf (stderr, ...) и записывает его в последний открытый файловый дескриптор или что-то в этом роде?

Zer0day 25.01.2023 23:32

@ Zer0day в сообщении журнала фиксации упоминается утилита svnadmin. Поэтому я не уверен, подходит ли код для операций на стороне клиента. Возможно, это больше для svnadmin и других утилит администратора.

Plimpus 25.01.2023 23:41

Если вы запустите svn … 2>&-, SVN запустится без стандартной ошибки (2>&- означает «закрыть файловый дескриптор 2»). Тогда первому открытому файлу будет присвоен файловый дескриптор 2. Но stderr использует файловый дескриптор 2, поэтому любое сообщение об ошибке будет отправлено в открытый файл. Запись завершится ошибкой, если файл будет открыт для чтения, а не для записи, но в противном случае сообщение об ошибке появится там, где вы этого не ожидаете. Это немного отличается от svn … 2>/dev/null, где стандартная ошибка перенаправляется на /dev/null, или svn … 2>/tmp/svn.log, где она переходит к именованному файлу.

Jonathan Leffler 26.01.2023 00:04

@JonathanLeffler Итак, каждый раз, когда мы используем дескриптор файла с open () или close (), этот дескриптор файла также будет использоваться для следующей операции open () или close (), верно? Это функции open() и close() из стандартной библиотеки C или функции linux close() и open()? Также относится ли это к другим функциям, наряду с open и close ?

Zer0day 26.01.2023 00:10

Официальное правило гласит: «open() — или любая другая аналогичная функция создания дескриптора файла, включая pipe() — будет использовать наименьший номер дескриптора файла, который в данный момент закрыт». Насколько я знаю, единственными исключениями являются dup2() (где вы указываете используемый дескриптор файла) и fcntl(F_DUPFD, …) (где вы указываете наименьший номер дескриптора файла для использования). Но если файловый дескриптор 2 закрыт (но 0 и 1 открыты), то первым доступным файловым дескриптором будет 2, и он будет возвращен open() или другим вызываемым коллегой.

Jonathan Leffler 26.01.2023 00:16

@JonathanLeffler Но мы должны вызывать fcntl для каждого дескриптора файла, который мы создаем после закрытия stderr, если мы хотим снова открыть stderr. Есть ли глобальный способ установить это? Значит, нам не нужно вызывать fcntl для каждого файлового дескриптора?

Zer0day 26.01.2023 00:43

Если вы знаете, что файловые дескрипторы 0, 1, 2 открыты (поскольку стандарт C предписывает, что они должны быть открыты, или потому что вы заранее проверили), а код в приложении (в данном случае SVN) никогда не закрывает ни один из этих дескрипторов , то нет необходимости постоянно проверять. Кажется, именно это и делает код, который вы цитируете — используйте /dev/null с файловыми дескрипторами 0, 1, 2, если они еще не открыты. И это позволяет избежать неприятностей. POSIX определяет поведение, которое я отметил в §2.14 Распределение файловых дескрипторов.

Jonathan Leffler 26.01.2023 01:40
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
9
68
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Боюсь, я не знаю о проблемах, специфичных для SVN, для решения которых предназначен этот код (он был зафиксирован более 18 лет назад). Но я думаю, что приведенное ниже резюме описывает потенциальную проблему на высоком уровне. Поэтому я предполагаю, что рассматриваемая часть кода предотвращает это:

Давняя практика Unix требует, чтобы приложения запускались с стандартные потоки ввода, вывода и ввода/вывода ошибок в файловых дескрипторах 0, 1 и 2 соответственно. Предположение, что эти файловые дескрипторы будет правильно настроен, настолько силен, что большинство разработчиков даже не задумываются проверить их. Так что интересные вещи могут произойти, если приложение запускать с одним или несколькими закрытыми стандартными файловыми дескрипторами.

Рассмотрим, например, запуск программы с файловым дескриптором 2. закрыто. Следующему файлу, который откроет программа, будет присвоен этот дескриптор. Если что-то затем заставляет программу писать (что она думает, что это) стандартный поток ошибок, этот вывод вместо этого будет идти в другой файл, который был открыт, вероятно, повредив этот файл. А злонамеренный пользователь может легко натворить беспорядка таким образом; когда setuid программы вовлечены, потенциальные последствия хуже.

Взято с https://lwn.net/Articles/347815/

PS Проверьте svn вину за эту часть кода . В нем есть лог-сообщение, описывающее цель этих проверок.

Спасибо за повтор. Я как бы понимаю это немного больше, но все еще не мог понять идею. Запуск программы с закрытым файловым дескриптором 2. Что означает файловый дескриптор stderr закрытый? Насколько я знаю, в unix есть только функция close(), которая закрывает любой файловый дескриптор. Так как же программа закрывает stderr? И допустим, мы его закрыли, как следующий файл, который мы открываем, назначается stderr. Я не эксперт, но я не знаю, как программа может открыть файл с помощью stderr. Можете ли вы уточнить эту часть немного больше?

Zer0day 25.01.2023 23:41

@Zer0day Я предлагаю вам обратиться в список рассылки dev@ Subversion, чтобы узнать точное назначение этого кода и какие проблемы он предназначен для предотвращения.

Plimpus 25.01.2023 23:44

Другие вопросы по теме