Вопрос

Я читал DJB «Некоторые мысли о безопасности после десяти лет Qmail 1.0» И он перечислил эту функцию для перемещения файлового дескриптора:

int_move (до, из) int; от; {если (значение == из) возврата 0; Если (fd_copy (to, from) == -1) return -1; близко (от); вернуть 0; }

Мне пришло в голову этот код не проверяет возвращаемое значение близко, поэтому я прочитал страницу человека на конец (2), и кажется, могу справиться с EINTR, в этом случае подходящее поведение, по-видимому, кажется, чтобы снова назвать близко с тем же аргументом.

Поскольку этот код был написан кем-то с гораздо более опытом, чем я в C и UNIX, и дополнительно стоял без изменений в qmail в течение более десяти лет, я предполагаю, что должен быть какой-то нюанс, который мне не хватает, что делает этот код правильным. Кто-нибудь может объяснить мне это нюанс?

Это было полезно?

Решение

Когда файловый дескриптор является DUP'D, как оно в fd_copy или dup2 Функция, вы получите более одного файлового дескриптора, ссылаясь на то же самое (то есть то же самое struct file в ядре). Закрытие одного из них просто уменьшит его ссылочный счет. Операция не выполняется в базовом объекте, если только это прошлой близко. В результате, такие условия, как EINTR а также EIO не возможно.

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

У меня есть два ответа:

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

Каждый системный вызов может вернуть EINTR, ECPPECALE, что блокирует, как READ (2) ждет на медленном человеке. Это более вероятный сценарий, и хороший «вход в эксплуатацию от терминала», действительно будет проверять на это. Это также означает, что запись (2) может потерпеть неудачу, даже при записи файла журнала. Вы пытаетесь зарегистрировать ошибку, которую генерируется регистратор или вы просто сдаетесь?

Другая возможность состоит в том, что его функция используется только в приложении (или части одной), которая сделала что-то, чтобы гарантировать, что вызов не будет прервана сигналом. Если вы не собираетесь делать ничего важного с сигналами, то вам не нужно отвечать на них, и это может иметь смысл замаскировать их все, а не обернуть каждую единую систему блокирующего вызова в EINTR Retry. За исключением того, что те, которые убьют вас, так что SIGKILL и часто SIGPIPE, если вы справляетесь с этим, бросившись, наряду с Sigsegv и аналогичными фатальными ошибками, которые в любом случае никогда не будут доставляться в правильное приложение для пользователя.

Во всяком случае, если все он говорит о том, это безопасность, то вполне возможно, ему не нужно повторить close. Отказ Если близко не удалось с EIO, то он не сможет его повторить, это будет постоянная неудача. Поэтому правильность его программы нет необходимости close преуспевать. Вполне может быть, что не нужно для правильности его программы, которая close быть повторенным на EINTR.

Обычно вы хотите, чтобы ваша программа вступила в лучшие усилия, чтобы добиться успеха, а это означает, что повторное взыскание на EINTR. Но это отдельная забота о безопасности. Если ваша программа разработана таким образом, чтобы некоторая функция не удалась по какой-либо причине, не является недостатком безопасности, то в частности, тот факт, что это случается Чтобы провалить EINTR, а не для постоянной причины, не является недостатком. Было известно, что DJB было достаточно самоуверенно, поэтому я бы не был удивлен, если он оказался какой-то причиной, почему он не нужно чтобы повторить, и, следовательно, не беспокоит, даже если это сделает, позволил бы его программе добиться успеха в промывку ручки в определенных ситуациях, где, возможно, он в настоящее время не удается (вроде бы явно отправить безвредной сигнал kill пользователем в решающем моменте).

Редактировать: Это происходит для меня, что повторное попытка на EINTR может потенциально сам быть недостатком безопасности при определенных условиях. Он представляет новое поведение в этот раздел Кода: он может набегать на неопределенный срок в ответ на потоп сигнал, где ранее это сделало бы одну попытку close а потом вернуться. Я не знаю, наверняка, что это приведет к тому, что это приведет к любым проблемам Qmail (в конце концов, close Сама не гарантирует, как скоро он вернется). Но если отказаться от после того, как одна попытка проще проанализировать код, то он может быть правдоподобным шагом. Или не.

Вы можете подумать, что повторение предотвращает недостаток DOS, где сигнал вызывает ложную неудачу. Но повторное попытка допускает другой (более сложный) дефект DOS, где сигнальный наводнение вызывает неопределенный стойл. С точки зрения двоичного двоина «Может ли это приложение было дозировано?», Что является видом абсолютного вопроса безопасности DJB, было заинтересовано в том, когда он писал Qmail и DJBDN, это не имеет значения. Если что-то может произойти один раз, то нормально это означает, что это может произойти много раз.

Только сломанные единицы когда-либо вернулись EINTR Без тебя явно прося его. Sane Semantics для signal() Включите перезапуску системных вызовов («Стиль BSD»). При создании программы в системе с семантикой Sysv (прерывая сигналы) вы всегда должны заменить звонки на signal() с звонками к bsd_signal(), который вы можете определить себя с точки зрения sigaction() Если это не существует.

Это стоит отметить, что нет Системы вернутся EINTR По получению сигнала, если вы не установили обработчики сигналов. Если действие по умолчанию осталось на месте, или если сигнал не имеет никакого действия, нельзя для прерывания системных вызовов.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top