В гостях у Оптерона и Целерона (Гладиаторские бои в Колизее)

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.



Ошибки процессоров INTEL

Сообщений 1 страница 18 из 18

1

В свое время "страшная" аббревиатура TLB стала причиной отставания корпорации AMD от Intel в производстве четырехядерных процессоров. Translation lookaside buffer (TLB) — это буфер сверхоперативной памяти центрального процессора, используемый для ускорения трансляции адреса виртуальной памяти в адрес физической памяти. Ошибка в TLB и стала причиной того, что запланированный на конец 2007 года выпуск четырехядерных процессоров AMD Barcelona был перенесен почти на полгода, так как компания честно пыталась исправить ошибку. Сейчас же Intel выпустила процессоры Core i7 (архитектура Nehalem), которые называет самыми быстрыми процессорами в мире.

Как и все современные процессоры, Core i7 также использует TLB. Но, как оказалось, первые Nehalem также имеют "баг", на который "напоролась" в свое время AMD. Однако корпорация из Санта-Клара, в отличие от конкурентов, отзывать процессоры на доработку не собирается. В официальной документации, посвященной новым процессорам, Intel прямо и заявляет, что в редких случаях ошибка в TLB может привести к "зависанию" операционной системы или выдаче критической ошибки. Для таких "бракованных" процессоров Intel предлагает скачать патчи к операционной системе и призывает создателей BIOS внести необходимые изменения. Так и представляем первых покупателей недешевых Core i7, которые перепрошивают BIOS и патчат ОС, как же. Официальных заявлений от самой компании пока еще не поступало. Официальное послание Intel.

Обновлено: Intel c возмущением опровергла шумиху, разгоревшуюся по поводу этой новости. Оказывается, все просто неправильно истолковали содержимое документа, считает корпорация. Компания опубликовала эту документацию именно для тех разработчиков, которые будут создавать программное обеспечение, заведомо вызывающее ошибку в TLB процессоров Core i7. То есть, хотите делать что-то, что может вызвать неправильную работу наших процессоров - тогда качайте эти апдейты и перепрошивайте BIOS. А никакой ошибки в TLB у нас не было и в помине. Интересное опровержение, надо будет долго поразмышлять :).
(c)news.techlabs.by/15_58926.html Игopь Дyльcкий

0

2

В четырехъядерных процессорах Intel найдена ошибка
10.12.2007 [18:33], Александр Бакаткин
Конец 2007 года, по всей видимости, запомнится наблюдателям целой эпидемией ошибок, допущенными разработчиками процессоров для вычислительных систем - не прошло и недели после сообщений о приостановке поставок продукции AMD, вызванной наличием ошибки в TLB-блоке кэш-памяти, как пришло сообщение о присутствии "бага" и в 45-нм процессорах Core 2 Quad, которые пока только ждут своего официального релиза. На этот раз сведениями поделился французский сетевой ресурс Hardware.fr, который со ссылкой на собственные источники информации сообщил о переносе сроков выхода четырехъядерных процессоров Intel с середины января на конец февраля - начало марта.

В чем именно заключается ошибка не сообщается, но известно, что в некоторых, очень редких ситуациях, она приводит к зависанию системы. Официальные представители компании отказались комментировать представленные сведения, заявив о точном следовании первоначальному плану выпуска процессоров на рынок - четырехъядерные решения для настольных компьютеров, как и ожидалось, появятся в первом квартале 2008 года. Не прояснилась и судьба уже выпущенных процессоров Core 2 Extreme QX9650, которые также содержат эту ошибку. А вот покупателям серверных четырехъядерных моделей Xeon волноваться не стоит - процессоры лишены "бага".

Таким образом, главный остающийся вопрос - официальные сроки релиза моделей Core 2 Quad Q9550, Q9450 и Q9300, которые, согласно пока неофициальным сведениям, должны быть представлены 20 января.

0

3

Процессоры Intel Core 2 содержат опасные ошибки
Theo de Raadt призвал в ближайшее время воздержаться от покупок процессоров Intel Core 2, так как данные процессоры содержат ошибки, которые могут позволить любому пользователю системы вызвать переполнение буфера.

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

Для полного списка официальных ошибок, см. Intel Core 2 65nm LGA 775 specification update

0

4

http://www.geek.com/images/geeknews/2006Jan/core_duo_errata__2006_01_21__full.gif

0

5

Critical update for Intel Core CPUs is out
Have Intel processor? Download the fix right now
By Mike Magee
Tue Jun 26 2007, 08:26 A COUPLE OF WEEKS ago, we heard that Dell was dealing with a certain situation considering Intel dual-core MCW and quad-core KC marchitecture, and that the company was releasing urgent BIOS and microcode versions for its line up.
We learned that the affected CPUs are the Core 2 Duo E4000/E6000, Core 2 Quad Q6600, Core 2 Xtreme QX6800, QX6700 and QX6800.

In the mobile world, people with the Core 2 Duo T5000 and T7000 need to visit Microsoft's site, while the server guys will want to use motherboard BIOSes if they do not rely on Microsoft Windows operating systems.

The affected servers are Xeon 3000, 3200, 5100 and 5300s - or just about every model from the second generation of Core marchitecture.

Oddly enough, Yonah - 32-bit Core Duo processor - isn't among the affected cores.

We are assured that no product recall will happen, and that La Intella took all appropriate steps in order to minimise damage to its public image, because if a product recall happened, Intel's credibility would be ruined for good.

Anyway, if you have a Core CPU based machine, go to the link below to download the update. AMD processors are not affected at all, in case you were wondering. µ

L'INQ

0

6

http://www.electrosad.ru/Processor/Intel2.htm

0

7

Дефекты проектирования Intel Core 2 Duo

Аналитический обзор с точки зрения безопасности

Крис Касперски

Процессоры Intel Core 2 Duo (и не только они одни!) содержат множество ошибок, приводящих к сбоям программного обеспечения, зависаниям операционной системы и даже возможности удаленного захвата управления компьютером! Часть ошибок обходится программным путем, часть – обновлением микрокода ЦП или прошивки BIOS, оставшиеся – неисправимы и требуют смены процессора. Насколько реальны эти угрозы? Попробуем разобраться!

Критикуя Windows (и отчасти Linux) за большое количество программных ошибок, мы «по умолчанию» закладываемся на непорочность аппаратного обеспечения, проектировщики которого ничем не отличаются от разработчиков операционных систем. До тех пор, пока процессоры были простыми (относительно операционных систем), выходили редко и тестировались тщательно – ошибки «кремниевых коней» носили единичный характер и учитывались разработчиками компиляторов. Сейчас они представляют разве что познавательный интерес. Легендарный «Hamarsoft's 86BUGS list», насчитывающий свыше сотни ошибок, недокументированных машинных команд и особенностей их поведения, последний раз обновлялся в 1994 году, после чего отправился на свалку истории, захлебнувшись в потоке дефектов, обнаруженных в первых моделях Pentium-процессоров, причем ни один из этих дефектов (за исключением знаменитой ошибки деления, описанной в одноименной врезке) до широкой общественности так и не дошел, ограничившись кругом производителей материнских плат, прошивок BIOS, разработчиков операционных систем/компиляторов и прочей технической элитой.

Возьмем, к примеру, инструкцию битового сканирования «BSF dst, src», копирующую в dst индекс первого установленного бита в src. Как вам нравится тот факт, что если src равен нулю, то содержимое dst становится неопределенным, то есть там может оказаться любой мусор, что серьезно осложняет отладку программ. Допустим, на машине разработчика установлен ЦП, оставляющий dst неизменным, и разработчик (или его компилятор) закладывается именно на такое поведение ЦП. А вот у конечного пользователя dst может сбрасываться в нуль, нарушая работоспособность программы и заставляя разработчика теряться в догадках, с какого момента программа пошла  разнос. Обычно в таких случаях все списывается на Windows или «у вас на компьютере вирусы, переустановите операционную систему… ах, вы уже ее переустановили?! ну тогда мы не знаем, разбирайтесь со своей машиной сами».

Кстати, это уже давно не ошибка, а вполне документированная особенность. Intel даже приводит псевдокод команды BSF во втором томе «Instruction Set Reference»:

Листинг 1. Псевдокод команды BSF с «узаконенной» ошибкой

IF SRC = 0

    THEN

           ZF := 1;

           DEST is undefined;

    ELSE

           ZF := 0;

           temp := 0;

    WHILE Bit(SRC, temp) = 0

    DO

           temp := temp + 1;

           DEST := temp;

    OD;

FI;

С такими «особенностями» можно еще и смириться, но куда прикажете девать эпизодически возникающие исключения на 486+, возникающие при загрузке регистра CR3 (указатель на каталог страниц) в регистр общего назначения? Конечно, непредвиденные исключения можно и подавить, что делает Linux и OpenBSD. Делать-то она это делает, но… местами. А местами не делает. Обращения к регистру CR3 происходят из многих функций ядра, а ядро пишет целая армия разработчиков, часть из которых осведомлена об этом дефекте, а часть – даже не подозревает. В результате мы имеем нестабильно работающую систему.

Windows не пытается сражаться с этим. А зря. Запрещение кэширования на запись в некоторых моделях процессоров разрушает содержимое кэша, откуда процессор продолжает брать ранее скэшированные данные (уже разрушенные), и чтобы программа не «грохнулась», кэш необходимо очистить программным образом, последовательно считывая ячейки памяти – неважно какие – лишь бы заполнить его. Поскольку считываемые данные не были модифицированы, то при последующем поступлении данных в кэш ранее прочитанные ячейки памяти не будут вытесняться ни в кэш вышестоящего уровня, ни в оперативную память, замещаясь новыми данными. На прикладном уровне такая ситуация, конечно, маловероятна, да и нельзя на прикладном уровне управлять кэшированием, но вот драйверы совсем другое дело! Если некоторый регион памяти используется для обмена данными с внешним устройством (видеоконтроллером или платой телеметрии), владельцы «неправильных» процессоров окажутся очень «рады» всевозможным артефактам на экране монитора и неверным телеметрическим результатам. Стоит ли удивляться, что x86 не используются в критических инфраструктурах, где работают простые и тщательно протестированные микроконтроллеры?

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

Производители ЦП ведут с дефектами проектирования ожесточенную борьбу, прогоняя каждую команду (а то и комбинации команд) через серию агрессивных тестов, результаты которых так или иначе отражаются в документации или же «specification updates». В частности, последние обновления спецификации на Intel Core 2 Duo в любой момент можно скачать с официального сайта Intel: http://www.intel.com/design/core2duo/do … #specupdt, раздел erraata которого на момент написания этих строк (май 2008) насчитывает 126 ошибок, многие из которых критические и затрагивают не только ядерный, но и прикладной уровень.

Немногим лучше обстоит ситуация с серверными процессорами: Intel Xeon Quad-Core 5400 и его младший собрат Xeon Dual-Core 5100 насчитывают по 54 официально признанных дефекта каждый. И даже Itanium 9000, рекомендованный фирмой Intel для критических инфраструктур (massive, mission-critical computing), хранит в своих недрах 85 «жуков», способных обрушить сервер в любой момент. А ведь это одно из самых дорогих и тщательно протестированных произведений Intel, ориентированное на корпоративный сегмент рынка, который ошибок не прощает и на котором помимо Intel имеются и другие игроки, впрочем, сталкивающиеся с теми же самыми проблемами.

Мир не совершенен, никто из нас не без греха. Обновлять микрокод ЦП, прошивку BIOS (а в критических случаях – и сами процессоры!) нужно так же регулярно, как накладывать заплатки на операционные системы и прочее программное обеспечение. Ах да, операционные системы… С них-то все и началось!

Intel Core 2 Duo со всеми ошибками, которые в нем только есть

…и грянул гром

Ознакомившись с очередной errata на Core 2 Duo, Тео де Раадт (Theo de Raadt), ведущий разработчик операционной системы OpenBSD, славящейся своей надежностью и защищенностью, пришел в ярость, и набросился на производителей Core 2 Duo с обличительными заявлениями в стиле: «Как дальше жить и что нам делать?!», тут же подхваченными прессой и ставшими достоянием широкой общественности, постепенно начинающей осознавать, что помощи нет и не будет. Ситуация очень серьезна – достаточно большое число ошибок не только приводит к краху системы, но и (теоретически) допускает возможность удаленного захвата управления, поскольку некоторые инструкции при определенных обстоятельствах выполняются не так, как ожидалось, например, программа, написанная на JavaScript, интенсивно работающая с кэшем, может вызывать направленный удар по памяти, искажая адрес возврата или другие указатели на функции.

Ряд ошибок процессора «сотрудничает» с ошибками программного переполнения. Широко распространена ошибка неявного приведения типов (кастинга) – signed int в unsigned int. Огромное количество программ, написанных на Си, хранят длину копируемого блока памяти в переменной типа signed int, передавая ее функции типа memcpy() и выполняя при этом проверку «if (len > MAX) return -1», забывая о том, что если len < 0, то данная проверка проходит на «ура», а вот в процессе передачи аргумента len функции memcpy() происходит неявное преобразование типов в unsigned int и, поскольку на x86-процессорах знаковый бит является старшим битом, то memcpy пытается скопировать по меньшей мере 2 Гб памяти (при 32-разрядном int). Вот именно, что «пытается». В ходе копирования функция непременно «врезается» в регион, недоступный на запись, и генерируется исключение, приводящее к аварийному завершению программы (хотя в Windows-системах есть надежда, что в процессе копирования удастся перезаписать адрес обработчика исключений до наступления исключения, перехватывая управления при его генерации, но техника SafeSEH предотвращает такой вариант развития событий). Однако в процессоре Core 2 Duo имеется целый класс ошибок, приводящих к преждевременному прерыванию копирования блока памяти, когда его размер превышает размеры адресного пространства. В нормальных программах такие ошибки никак не проявляются, поскольку никто из программистов не копирует блоки памяти по 4 Гб или более того, но вот хакеры… им преждевременное прерывание копирования очень на руку – отличное средство для «дозированного» переполнения буфера в условиях неявного преобразования signed int в unsigned int.

Разработчики OpenBSD попытались заткнуть самые крупные дыры, переписав код ядра так, чтобы исключить или хотя бы снизить вероятность событий, ведущих к проявлению ошибок, но вот остальные программистские коллективы, выражаясь образным языком, даже не почесались, и в первую очередь это относится к новомодному Server 2008, для которого заплаток нет и не предвидится. Что же тогда говорить о «морально устаревшем», но все еще работающем парке Windows 2000, XP, Server 2003?!

Но вернемся к исходному сообщению Тео де Раадта, опубликованному в конце июня 2007 года, когда обнаруженных ошибок было вдвое меньше, чем сейчас: http://marc.info/?l=openbsd-misc&m=118296441702631.

Сенсация или реальная угроза?

Интересно разобраться, что же так напугало Тео де Раадта и насколько велика вероятность атаки на Core 2 Duo, тем более, что за время, прошедшее с момента публикации, количество обнаруженных ошибок удвоилось. Анализировать ошибки мы будем в порядке, обозначенном де Раадтом, с учетом специфики операционных систем семейства NT (Windows 2000, XP, Server 2003/2008, Vista), Linux и линейки BSD – Free, Net и Open, приводя официальную информацию из errata со всеми выкладками и рассуждениями, а местами – сценариями реализации атаки.

AI65: Температурное прерывание не генерируется
при выходе текущей температуры за пределы

n  Проблема: когда DTS (Digital Thermal Sensor – цифровой температурный сенсор) достигает одного из установленных пороговых значений, процессор генерирует прерывание, протоколируя данное событие в журнале (IA32_THERM_STATUS MSR (019Ch) биты [9,7]). Вследствие конструктивного дефекта при достижении пороговой температуры (что индицируется MSR-регистром IA32_THERM_STATUS бит [31]) DTS не генерирует прерывания и не устанавливает биты журнала, даже если было пройдено одно из пороговых значений.

n  Последствия: при выходе температуры кристалла за пороговые границы процессор не генерирует прерывания.

n  Решение: не найдено.

В общем, не такой уж и страшный дефект, хотя… учитывая, что:

n  99% машинного времени процессор «спит», практически не нагреваясь;

n  при активной работе одного или нескольких блоков процессора тепловыделение резко возрастет;

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

Некоторые производители используют внешний термодатчик, но большая часть полагается на показания процессора – так и дешевле, и точнее, но если DTS не работает, то возникает прямая угроза перегрева кристалла, особенно если хакер загрузит его на полную мощность, что очень легко сделать Java-скрипитом или Flash-роликом. Кратковременный перегрев для ЦП в общем-то не опасен, но вот систематический «перекал» ведет к необратимой деградации кристалла. Первым, как правило, гибнет кэш, и система начинает выдавать критические ошибки приложений и выбрасывать голубые экраны смерти.

Таким образом, атаковать систему не нужно. Она и сама умрет через какое-то время.

AI79: Инструкции записи с префиксом REP
при определенных обстоятельствах могут завесить ЦП

n  Проблема: во время выполнения серии инструкций записи, предваренных префиксом REP (REP STOSx/MOVSx), содержимое промежуточного буфера может выгружаться в память до того, как туда поступят актуальные данные. Поведение процессора зависит от порядка выполнения инструкций, временных характеристик «спекулятивных» переходов и временных характеристик некэшируемого буфера записи. Этот дефект распространяется на все операции записи с префиксом REP.

n  Последствия: проявления дефекта варьируются от зависания процессора или операционной системы.

n  Решение: дефект можно обойти на уровне BIOS.

Да… тут есть о чем задуматься. Инструкции REP STOSx/MOVSx относятся к числу самых популярных. Функции инициализации и копирования памяти в большинстве случаев реализованы именно так, и работают они как на прикладном, так и на ядерном уровне. Трудно представить, что произойдет, если вместо записываемых данных в память будет выгружен мусор, случайно оказавшийся в буфере или… умышленно засунутый туда хакером («засунутый» в смысле оставшийся от предыдущей серии операций записи).

К сожалению, Intel не раскрывает технических деталей, и нам остается только догадываться, при каких именно условиях возникает преждевременный «выброс» данных в память. То, что дефект устраним на уровне BIOS, – это хорошо, но вовсе не факт, что за это не придется расплачиваться производительностью (есть подозрение, что BIOS просто изменяет диапазоны временных характеристик подходящим образом).

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

AI43: Параллельные записи в «чистые» страницы памяти
на многопроцессорных системах ведут к неопределенному поведению

n  Проблема: когда логический процессор осуществляет запись в «чистую» (т.е. ранее не модифицированную) страницу памяти, а другой логический процессор в это же самое время либо осуществляет запись в эту же страницу, или явным образом устанавливает бит модификации в соответствующем поле страничного каталога, «внутриусобные» войны между логическими процессорами, заключенными в один физический кристалл, при определенных обстоятельствах приводят к неопределенному поведению системы.

n  Последствия: данный дефект приводит к непредсказуемому поведению системы и возможному зависанию.

n  Решение: дефект может быть устранен на уровне BIOS.

Ох, столько мудрости в этих словах «неопределенное поведение». Инженеры их очень любят. Инженеры вообще любят неожиданности, подстерегающие их в непредвиденных местах. Но чего тут гадать. Все предельно ясно.

Флаг модификации, являясь разделяемым ресурсом, весьма придирчив к порядку, и все операции с ним должны быть упорядочены теми или иными механизмами синхронизации. Даже не сколько сам этот бит, а его окружение. Модифицировать отдельные биты процессор не обучен и он оперирует машинными словами (длина которых не обязательно равна двум байтам, в данном контексте – это минимальная порция обмена с памятью, которая, на Core 2 Duo по одним данным составляет 16, по другим – 32, а по третьим – 64 бита). Процессор сначала читает машинное слово целиком в свой внутренний буфер, взводит/сбрасывает один или несколько бит, после чего записывает его обратно.

А теперь представим, что процессоров у нас два и они одновременно обращаются к одному и тому же слову. Тогда повторная установка уже установленного бита приведет к его сбросу! Операционная система будет считать, что данная страница не была модифицирована и потому при нехватке памяти не станет выгружать ее в файл подкачки, что приведет к необратимой потери данных!

Как это можно использовать для атаки?! Завесить систему – это ерунда,  при желании можно разрушить дисковый кэш, для этого нужно организовать операции записи одних и тех же файлов из двух (или более) разных потоков, параллельно с этим «съедая» всю свободную оперативную память. На NTFS самым главным файлом является $MFT, хранящий информацию обо всех остальных файлах тома. Прямое обращение к нему операционная система блокирует, но вот косвенное – создание/удаление/изменение атрибутов одних и тех же файлов из разных потоков – допускает даже с гостевыми правами. А крах дискового тома – это пострашнее зависания.

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

Грубым решением проблемы является переход в однопроцессорный режим, что осуществляется добавлением ключа /ONECPU в boot.ini). Конечно, производительность при этом падает, но если целостность данных превыше производительности – это не такая уж и безумная мера. А надеяться на производителей BIOS… где гарантия, что они действительно справятся с ошибкой?!

AI39: Запрос кэш-линейки L1-кэша из одного ядра
разрушает модифицированную кэш-линейку другого ядра,
приводя к непредсказуемому поведению системы

n  Проблема: когда запрос данных из Ядра 1 приводит к «промаху» L1-кэша, запрос перенаправляется к L2-кэшу. Если же данная кэш-линейка уже находится в L1-кэше Ядра 2 и была им модифицирована, при определенных обстоятельствах Ядру 1 возвращается неверный результат.

n  Последствия: непредсказуемое поведение системы.

n  Решение: BIOS может справиться с этой проблемой.

Как известно, многоядерные процессоры имеют разделяемый (один на всех) L2-кэш и «индивидуальные» L1-кэши, фактически являющиеся частью ядра. В грубом приближении мы имеем обыкновенную многопроцессорную систему с разделяемой внешней памятью и внутрипроцессорной кэш-памятью. Для поддержания памяти в согласованном состоянии используются специальные когерентные протоколы, разработанные десятки лет тому назад. Казалось бы, в чем проблема?!

А в том, что создатели Core 2 Duo или забыли о когерентности (ну это уж вряд ли), либо, что более вероятно, реализовали ее неправильно. Насколько часто разные ядра работают с одними и теми же порциями данных? Очень часто! Ведь при переключении контекстов потоки, стартовавшие на одном ядре, рано или поздно оказываются на другом! Последние версии операционных систем линейки NT, Linux и BSD наконец-то научились отличать ядра от физических процессоров (в многопроцессорных системах) и потому стараются по возможности избегать переброски потоков с одного ядро на другое, поскольку при этом придется заново заполнять L1-кэш. Есть даже специальные API-функции для закрепления потоков за определенным процессором (ядром), но на практике они не используются, и программисты предпочитают доверять системному планировщику, алгоритм которого оптимизируется разработчиками операционной системы с учетом «характера» процессоров, имеющихся на рынке. Но в распоряжении планировщика – сотни потоков и обычно только два (редко четыре) ядра. Так что избежать «передислокаций» потоков невозможно, точнее, возможно, но уж слишком неэффективно.

Как можно использовать данный дефект для атаки? Самое простое – ничего не делать с системой. Она и сама упадет. Разрушение дисковых данных достаточно маловероятно, хотя и не исключено на 100%, а вот критические сбои приложений и голубые экраны смерти – вполне ожидаемое явление. Действительно, если программа что-то записала в память (на самом деле в кэш, но это уже не важно), а при последующем чтении не обнаружила никаких изменений, тут может произойти все что угодно.

Автору удалось реализовать разрушение кучи (динамической памяти) путем циклического выделения/освобождения крошечных блоков в Java-скрипте, следствием чего явился крах браузера. Чисто теоретически возможно разрушить кучу так, чтобы передать управление на shell-код, но для этого необходимо учитывать множество специфичных деталей, неизвестных удаленному атакующему, хотя в принципе достаточно предсказуемых.

Шторм запросов к любому драйверу (например, шторм IP-пакетов) также потенциально способен вызывать крах системы, но, учитывая, что шторма зачастую вызывают BSOD даже на «правильных» процессорах (из-за ошибок синхронизации, допущенных разработчиками драйверов), очень трудно определить, с каким дефектом мы имеем дело: с программным или аппаратным. Тем не менее хакерский потенциал у атак данного типа весьма весомый, что главным образом обуславливается простотой их реализации.

Самое непонятное в этой истории – какое отношение имеет BIOS с «разборкам» внутри процессора?! Единственное разумное предположение – BIOS просто заливает обновленный микрокод, предоставленный Intel. По-другому справиться с проблемой навряд ли получится.

AI90: Атрибут доступа к странице памяти
может быть установлен до генерации исключения

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

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

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

Вот мы и добрались до дефекта, особо отмеченного Тео де Раадтом в качестве подходящего кандидата для атаки на операционные системы (за исключением OpenBSD в конфигурации по умолчанию). Что же это за операционные системы такие?!

В NT лимиты сегментов кода, данных и стека «распахнуты» на все адресное пространство, нижнюю половину которого занимает прикладной код, верхнюю – операционная система. Так что за пределами кодового сегмента вообще ничего нет. Да и чтобы добраться до его конца, необходимо сначала как-то попасть на уровень ядра, где можно делать что угодно и без всяких дефектов процессора (правда, в Core 2 Duo есть еще один интересный дефект, обнаруженный автором и не описанный в последней errata – при выполнении кусочка инструкции, находящегося в самом конце кодового сегмента, декодер, определяя длину инструкции по первым байтам, пытается считать ее продолжение, которого нет, в результате чего происходит «заворот» в начало сегмента, первой странице которого также присваивается атрибут доступа, после чего генерируется исключение, которое хакеру необходимо отловить, чтобы система не свалилась в BSOD, но что это даст?!

Младшие страницы адресного пространства специально сделаны недоступными в NT для отлова обращения по нулевым указателям, свидетельствующих о том, что программа обращается к невыделенной области памяти, и Windows передает ей исключение, которая та может обработать тем или иным образом, но чаще всего обработчик конструктивно непредусмотрен, и тогда система завершает работу приложения в аварийном режиме.

Установка атрибута доступа на первую страницу приведет к подавлению исключения, и программа упадёт не в момент обращения к нулевому указателю, а чуть позже – когда попытается обработать считанный оттуда мусор. Не слишком-то большое достижение, к тому же легко реализуемое на прикладном уровне без обращения к дефектам процессора).

Правда, 16-разрядные приложения имеют свои собственные 16-разрядные лимиты, и теоретически благодаря ошибке в процессоре атакующий может получить доступ к данным, которые ему читать не положено. В смысле по атрибутам страниц не положено, а так… если атакующий может запускать приложения, то отформатировать диск или удалить все файлы – быстрее и надежнее.

А вот из 32-разрядного приложения вызвать 16-разрядное, ну не то чтобы невозможно, но все-таки достаточно сложно (имеется в виду вызов из shell-кода, исполняющегося в 32-разрядном приложении). Другими словами, на Windows этот дефект не оказывает ровным счетом никакого воздействия.

А что на счет BSD и Linux? Штатные ядра также исповедуют плоскую модель. Кодовый сегмент находится в самом конце адресного пространства, и ничего интересного за ним нет. Некоторые защитные пакеты, разработанные еще в ту далекую эпоху, когда процессоры поддерживали атрибут, «исполняемый» только на уровне селекторов, а необходимость защиты стека, кучи и данных от исполнения заброшенного хакером туда shell-кода уже назрела – произошло вот что: нестандартные ядерные расширения урезали лимиты стека и сегмента данных (расположенных в начале) и отобрали у них атрибут «исполняемый». А за ними расположили сегмент кода. Вот если бы они поступили в обратном порядке (сначала код, потом стек и данные), то у хакеров была бы потенциальная возможность доступа к недоступным данным, вот только… стек и куча доступы и так… без всяких дефектов процессора.

Конечно, можно предположить, что где-то есть операционная система, в которой сначала идут пользовательские сегменты кода и данных, а потом расположен сегмент операционной системы, хранящий данные, защищенные от чтения, поскольку, будучи прочитанными, они позволят повысить уровень своих привилегий, например, но… если такая операционная система и есть, то это не Linux, не Windows, не BSD и не QNX… а какая-то студенческая поделка. Вопрос: какой интерес ее атаковать?! Короче, на этот дефект процессора можно вообще не обращать внимания. Ну разве что при разработке новых операционных систем, радикально отличающихся от уже существующих.

Windows использует «плоскую» модель памяти с «распахнутыми» границами сегментов

AI99: Обновление атрибутов директории кодовых страниц
без «инвалидации» TLB может привести к некорректной обработке исключения #PF

n  Проблема: исключение #PF (Page Fault – страничный отказ) обычно обрабатывается с другими исключениями, перечисленными в порядке увеличения приоритета: #DB (Debug Exception – отладочное исключение), Segment Limit Violation (исключение выхода за пределы Сегмента), #GP (General Protection Fault – общее нарушение защиты). Вследствие дефекта проектирования, #PF исключение обрабатывается некорректно, при наступлении одного из следующих событий:

m PDE (Page Directory Entry – запись каталога страниц) модифицируется без «инвалидации» (to invalidate – делать недействительным) соответствующей записи TLB (Translation Look-aside Buffer – буфер обратной трансляции);

m транзакция исполнения машинной инструкции находится на стыке двух страниц, причем выполняется одно из следующих условий:

m линейный целевой адрес соответствует модифицированной PDE;

m PTE (Page Table Entry – запись таблицы страниц) для целевого линейного адреса имеет сброшенный бит доступа;

m транзакции предшествует одно из двух следующих исключений:

m #DB и #PF;

m #GP и #PF.

n  Последствия: программное обеспечение должно либо отслеживать некорректное #PF исключение, предшествующее #GP исключению, так же как #PF исключению перед #DB.

n  Решение: не найдено.

Наконец-то мы добрались до дефекта, который Тео де Раадт характеризует как «ну вот, теперь нам Intel говорит, что TLB нужно обрабатывать совершенно иным путем, не похожим на старый». Ох и врет! Intel ничего такого не говорит, признавая за собой дефект и расписываясь в бессилии найти приемлемое обходное решение. Дефект, конечно, серьезный, и остается только удивляться, как существующие операционные системы ухитряются работать на Core 2 Duo, не падать каждые шесть-семь минут (хотя, возможно, они и падают, но не так часто).

Выход только один – ждать новой ревизии процессора, с исправленной ошибкой обработки TLB (после чего все будет «как при бабушке»), либо же модифицировать (причем весьма значительно) ядро операционной системы, чтобы оно стабильно работало и на дефектных ЦП. Microsoft выпуском такой заплатки не озаботилась, хотя похоже, что при ее манерах обращения с TLB обозначенный дефект не особо и мешает. А вот де Раадт доработал ядро OpenBSD, застраховав систему от возможных «сюрпризов» со стороны процессора. Естественно, ядро исправить (да еще таким необычным способом) – это не просто две строчки кода местами поменять, так что его можно понять. Кому хочется отдуваться за чужие ошибки?! А между тем ошибок в процессорах много…

Заключение

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

Нетронутую целину дефектов железа хакеры только-только начали осваивать. До сих пор не представлено ни одного proof-of-concept exploit и не зафиксировано случаев вторжения, основанных на ошибках ЦП, однако… в атмосфере определенно что-то происходит. Что-то такое.., не предвещающее ничего хорошего.

Впрочем, не будем изображать из себя пророков, предоставив событиям развиваться своим чередом, а сами тем временем приложим максимум усилий по обеспечению собственной безопасности, скачивая свежие прошивки BIOS и выбирая продукцию тех производителей, которым можно верить и которые действительно борются с дефектами процессоров, отмечая свои достижения в сопроводительных файлах. Что же касается операционных систем, то в линейке BSD – OpenBSD несомненный лидер, Linux все на одно лицо, и особой разницы между ними нет (у одних одни недостатки, у других – другие). Microsoft похоже бороться в ошибками процессоров вообще не собирается, а это большой минус.

Приложение

Ошибка деления в Pentium

Самая громкая ошибка в Pentium была обнаружена в 1995 году и продемонстрирована на следующем примере: x – (x/y)*y, результат которого (если только y != 0), должен быть равен нулю, однако при определенных значениях x и y (x = 4195835, y = 3145727) процессор выдавал… 256! Потрясающая точность, однако!

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

С тех пор сообщений об ошибках в ЦП как будто бы не отмечалось. И потому заявление Тео де Раадта, что Core 2 Duo содержит огромное количество ошибок, многие из которых допускают удаленный захват управления, стало очередной сенсацией года.

Текст сообщения Тео де Раадта, опубликованный в конце июня 2007 года

В настоящий момент разработчики программного обеспечения и производители железа заняты разработкой «костылей», исправляющих серьезные ошибки в процессорах серии Intel Core 2, содержащих адское количество багов, и некоторых из этих багов не просто мелкие дефекты проектирования, а реальные дыры, которые несомненно могут быть использованы для атак с прикладного уровня. Ряд ошибок невозможно ни исправить, ни найти обходное решение для предотвращения их возникновения. Intel ограничивается тем, что предоставляет техническую информацию производителям BIOS и ведущим разработчикам коммерческих операционных систем. Open Source-сообщество брошено на произвол судьбы.

Вот полная (текущая) errata: http://download.intel.com/design/proces … 327914.pdf (ссылка не работает, т.к. номер спецификации постоянно обновляется, и последняя версия может быть найдена по базовой ссылке: http://www.intel.com/design/core2duo/do … _core2duo+ tab_techdocs#specupdt. – Прим. переводчика):

n  Мы готовы биться об заклад, что ошибок на самом деле гораздо больше, чем анонсировано – с каждым месяцем errata становится все больше и больше (так оно и оказалось в последствии. – Прим. автора).

n  Intel существенно преуменьшает значимость обнаруженных ошибок – практически все операционные системы вляпаются в эти баги.

n  В сущности MMU (Memory Management Unit – блок управления памятью) подвергся существенным конструктивным изменениям и работает совсем не так, как в предыдущем поколении x86-процессоров. Мало того, что он превратился в сплошное скопище «тараканов», Intel сделала решительный шаг вперед, определив, по ее выражению, «новые методы обработки страничных таблиц» (см. стр. 58 – тут не совсем понятно, что именно смотреть и где, поиск по фразе в Google выдает ссылки только на сообщение Тео де Раадта и ни одного документа от самой Intel. – Прим. автора).

n  Некоторые ошибки имеют прямое отношение к технике «переполнения буферов» (самая популярная разновидность атак на сегодняшний день. – Прим. автора), где защита от записи или атрибут «неисполняемый» нагло игнорируются процессором. Другие ошибки связаны с некогерентностью (т.е. несогласованностью) инструкций сопроцессора или же производят разрушения памяти – вне области, отведенной в пользование прикладного процесса, посредством последовательности «обычных» (т.е. непривилегированных) машинных инструкций.

n  Все это кажется совершенно невероятным, но это факт!

Вот краткий сводный конспект ошибок Core 2 Duo для нетехнических людей: http://www.geek.com/images/geeknews/200 … __full.gif (тут Theo de Raadt слегка противоречит сам себе, поскольку приводит конспект совсем другой errata, с другими ошибками и другой нумераций, поэтому перечисленные ниже номера ошибок не имеют к нему никакого отношения. – Прим. автора).

Примечание: некоторые ошибки типа AI65, AI79, AI43, AI39, AI90, AI99 пугают нас так, что душа, минуя пятки, спускается прямо в преисподнюю. Эти «штучки» не могут быть исправлены программным путем, т.е. посредством модификации исходного кода операционной системы и/или приложений, и некоторые из них затрагивают все операционные системы, выпущенные до середины 2008 года, поскольку MMU любых Intel/AMD и совместимых с ними процессоров всегда управлялся одним и тем же способом. И вот теперь Intel говорит нам, что TLB-буферы, входящие в состав MMU, должны «сбрасываться» на совершенно иной манер. Но даже сделав это, ошибки процессора, перечисленные в errata, не позволят создать стабильно работающей операционной системы.

Как уже говорилось, в обозначенном списке скрываются 20-30 ошибок, которые не могут быть преодолены программным путем на уровне операционной системы, и эти ошибки создают потенциальную угрозу для атаки на машину. Готов поставить на заклад кучу денег, что по крайней мере 2-3 из них реально способны на это.

Например, AI90 подходит для атаки на некоторые операционные системы (двоичные сборки OpenBSD в конфигурации по умолчанию к ним не относятся). В настоящий момент я бы не рекомендовал приобретать машины, построенные на базе Intel Core 2, до тех пор пока дефекты проектирования не будут исправлены (что, по моим подсчетам, займет больше года). Intel должна стать более «прозрачной» (а не зажимать технические детали, рассылая их только разработчикам BIOS и коммерческих операционных систем. – Прим. автора). Между тем мне хотелось бы отметить, что AMD с каждым днем становится все менее и менее полезной для Open Source-сообщества, поскольку количество ошибок, обнаруженных в ее процессорах, растет не менее стремительно.

0

8

Компания Intel официально подтвердила наличие ошибки в процессоре Intel Pentium III Xeon с тактовой частотой 900 МГц. Представитель компании заявил, что проблема была вызвана особенностями производственного процесса, что заставило производителя процессоров поменять планы.

Представитель компании сказал буквально следующее: “Мы подтверждаем информацию о случае с процессором Intel Pentium Xeon с тактовой частотой 900 МГц и кэш памятью второго уровня объёмом 2 Мб. Однако обнаруженная проблема появляется только при испытаниях в лаборатории и не известно ни одного случая проявления этой проблемы при работе процессора в системах конечных пользователей”.

Тем не менее, руководство Intel приняло решение изменить производственный процесс, что вызвало перерыв в поставках процессора Intel Pentium III Xeon 900 МГц как минимум до начала августа. Как утверждается, проблема не затрагивает другие процессоры линейки Pentium III Xeon. Заказы на процессор Intel Pentium III Xeon 900 МГц будут выполнены за счет поставок процессоров Intel Pentium III Xeon 700 МГц по желанию клиента.

Источник: the inquirer

0

9

Линус Торвальдс прокомментировал ошибки в Core 2 Duo

Обращение Тео де Раадта, публично заявившего о том, что процессоры Intel Core 2 Duo содержат "адское количество ошибок", вызвало не только живое обсуждение в форумах, но и реакцию со стороны иконы сообщества Open Source, Линуса Торвальдса.
По его мнению, архитектура Core содержит в себе меньшее количество ошибок сравнительно с другими потребительскими процессорами.
Объемность документа, описывающего ошибки Core 2 Duo, Линус объяснил тем, что их тестированию уделяется гораздо большее внимание, нежели большинству других CPU.
Со стороны Intel выступил Ник Кнуппфер, заявивший о том, что самой Intel уже выпущены BIOS для своих продуктов, устраняющий ошибки. Для сторонних же производителей всегда доступны апдейты, с помощью которых можно устранить проблемы, потенциально могущие привести к переполнению буфера и т.п.
В связи с ситуацией, получившей резонанс благодаря Раадту, уместно будет вспомнить довольно известный дефект процессоров Pentium, ошибку в блоке операций с плавающей запятой, "Pentium FDIV bug". Эта история стоила компании довольно много, даже, несмотря на тот факт, что сбой в вычислениях наблюдался лишь примерно в одной операции из 9 млрд.
В данной ситуации конкретных доказательств уязвимости Core 2 Duo пока не представлено, стало быть, владельцам данных процессоров беспокоиться не о чем.

0

10

Представьте, что сейчас 1986 год. И представьте, что вы - ныне покойный Ричард Фейнман (Richard Feynman). Звонит телефон, вы поднимаете трубку. Звонит Уильям Грэхэм (William Graham), исполняющий обязанности администратора в NASA1. Вы знаете, что это не может быть просто дружеский звонок, поскольку космический челнок Челленджер потерпел катастрофу несколько дней назад, 28 января 1986 года. Вы правы. Он звонит для того, чтобы просить вас принять участие в работе комиссии по исследованию причин катастрофы Челленджера. В сущности, NASA просит вас, свежеиспеченного Нобелевского лауреата, выступить в роли главного исследователя неисправностей для одного из самых печальных инцидентов в NASA в современной истории2. Вы принимаете предложение с трепетом. В конце концов, вы можете быть Нобелевским лауреатом, но вы не специалист по ракетам. Вы не участвовали в разработке космического челнока. Вы не знакомы с компонентами и системами космического корабля. Вы не имеете представления, какого рода информация записывалась в ходе рокового полета Челленджера. Вы не представляете себе состояние или полезность документации. Единственный ключ, который у вас есть, - это ваши визуальные наблюдения, что пламя, как кажется, выходило из правого топливного бака. Как вы будете решать задачу по поиску причины катастрофы?

В действительности, доктор Фейнман обнаружил причину инцидента, перемещаясь по всей стране и беседуя с инженерами и персоналом и не поддаваясь политическому давлению. В конечном итоге он провел свой знаменитый настольный эксперимент с образцом от одного из уплотнительных колец с челнока и стаканом ледяной воды для доказательства своей теории3 в ходе пресс-конференции в прямом эфире4.

К счастью, наша работа по устранению ошибок в программных системах намного легче той задачи, с которой столкнулся доктор Фейнман. В большинстве случаев мы можем попытаться воспроизвести ошибку, чтобы удостовериться, что мы полностью понимаем ее причины и следствия. Ученые NASA не имели такого преимущества. Они не могли воспроизвести ошибку, взорвав другой космический корабль. Более того, доктор Фейнман должен был представить формальный отчет о своих открытиях для общественной поверки и, что еще хуже, должен был бороться с политическим давлением со стороны официальных лиц NASA. Когда в последний раз мы должны были делать нечто подобное при устранении ошибок? В индустрии программного обеспечения мы очень мало делаем того, что можно назвать посмертным анализом ошибки. Мы не задаем таких вопросов, как, каким образом ошибка была обнаружена, как она возникла и что мы можем сделать, чтобы предотвратить ее. Если мы все же проводим посмертный анализ, мы так редко документируем наши открытия, что наше знание недоступно другим людям.

Во многих смыслах наша книга - это кульминация многих лет посмертного анализа ошибок, о которых мы узнали и которые провели сами. В главе 12 мы покажем вам, как анализировать ошибки, как увеличить ваше коллективное знание о процессах формирования ошибок и как это знание поможет нам избежать одних и тех же ошибок и создавать лучшее программное обеспечение в будущем. Действительно ли посмертный анализ ошибки поможет нам создать лучший продукт? Мы считаем, что ответ на этот вопрос - да! В 1981 году фирма NEC осуществила план, призванный помочь разработчикам программ и менеджерам проектов учиться на ошибках. Был создан каталог ошибок, наблюдавшихся во многих корпоративных проектах. Это поддержало разработчиков в поисках причин отказов программ и в предотвращении их повторного появления. За 10 лет, прошедших с запуска проекта, разработчики извлекли много уроков и стали способны применять этот опыт для повышения своей производительности и понижения числа ошибок5.

Инициатива NEC началась с каталога проблем и решений. После, обучившись находить причинно-следственные связи между проблемами, разработчики стали способны формулировать контрмеры для решения этих проблем. Мы начнем с того же.

Сценарий
В этой главе мы собрали для изучения набор программных ошибок. Большинство этих ошибок довольно хорошо известны и, как правило, хорошо описаны, поскольку их появление было общественно-значимым событием и многие имели серьезные последствия. Хотя достаточно банальные и избитые, эти ошибки все же способствуют наилучшему изучению конкретных случаев. Проблема состоит в том, что далеко не каждый связан с проектами такого масштаба и столь же критичными для безопасности, так что трудности, которые испытали эти программисты, могут показаться чем-то не связанным с вашими повседневными задачами, поэтому мы также включили несколько примеров ошибок из нашей собственной практики разработки программного обеспечения. Наши персональные ошибки являются более приземленными и не связаны с взрывами и потерями многих миллиардов долларов. Тем не менее в этой книге мы показываем ошибки, созданные другими, для иллюстрации различных положений. Мы показываем эти ошибки не для забавы. Наша цель - изучить события, окружающие эти знаменитые и не очень знаменитые ошибки, для того чтобы мы могли на них учиться.
Распределенные компьютерные системы из «реальной жизни»
Парад ошибок начинается примерами с двух моих предыдущих мест работы. Первая ошибка просуществовала несколько часов и была быстро устранена. Это был урок для второй ошибки. Девять месяцев спустя, вскоре после того как я начал работать в другом месте, я столкнулся с похожей ошибкой. Однако в новой компании проблема проявила себя за два месяца до моего прихода. Серьезность первой ошибки была такова, что она нарушала работу всей системы. Вторая ошибка, хотя и устойчивая, не была фатальной, она просто вызывала легкое раздражение, а не общую катастрофу.
История: компания Y
Был конец 1999 года, и я работал в одной Интернет-компании, которая обслуживала финансовые отчеты в Интернете. Назовем ее компания Y. Архитектура систем, обслуживающих финансовые отчеты, очень проста: Web-запрос приходит через один из многочисленных Web-серверов. Web-сервер передает запрос менеджеру нагрузки, и менеджер нагрузки доставляет запрос к одному из четырех серверов отчетов циклическим образом. Сервер отчета выбирает информацию из базы данных для генерации отчета.
Однажды сигналы тревоги начали сыпаться со всех сторон. Сервера отчетов выходили из строя один за другим. Сервер останавливался, перезапускался несколькими минутами позже и снова останавливался через несколько минут. Это случалось со всеми серверами. Частота поступления запросов не была очень высокой, не была она и какой-то необычной. Перезагрузка машины, кажется, не помогала. Сетевые операторы не имели представления, что вызвало этот хаос, и была вызвана команда разработчиков. Поскольку я разрабатывал и реализовывал коммуникационную инфраструктуру, используемую внутренними серверами, меня попросили помочь. Команда разработчиков подозревала, что модуль распределения нагрузки в коммуникационной инфраструктуре был неисправен и сервера останавливались из-за перегрузки.

Коммуникационная инфраструктура имела встроенные возможности протоколирования и трассировки, которые были деактивированы в конечном продукте. Первое, что я сделал, это включил эти возможности, чтобы определить, что же система делает. Протокол, сформированный сервером отчетов, мало что прояснил для меня. В протоколе была масса сообщений об ошибках, но ни одно из этих сообщений ничего не описывало. Однако сразу перед тем, как сервер отчетов претерпевал сбой и перезапускался, в протокол попадало сообщение, что сервер отчета остановлен. Я спросил у инженера, что означает это сообщение, но его ответ был несколько загадочным. Это было что-то о том, что программа перезапускает себя, когда считает, что есть какая-то проблема. В это время я рассматривал файлы протоколов, полученных от менеджера нагрузки, и увидел, что он все время обращается к одному и тому же серверу. Я немедленно предположил, что механизм распределения нагрузки работает неправильно и что менеджер загрузки перегружает сервер отчета, заставляя его перезапускать себя.

Я проинформировал группу о моих предположениях и вернулся к своему столу, проверять код, выискивая потенциальные ошибки. Ничего не бросалось в глаза, и я подумал о замечании инженера, что сервер отчета разработан так, чтобы перезапускаться, когда он считает, что существует проблема. Я решил выяснить, какого рода проблемы могли бы вынудить сервер перезапуститься. По существу сервер отчетов поддерживал 20 потоков одновременно и каждый запрос к серверу занимал 1 процесс. Ожидалось, что в нормальных условиях каждый процесс заканчивает обработку в течение 1-2 секунд. Данный сервер отчета не считался очень стабильным и имел факты подверженности ошибкам. Поэтому в сервер была встроена логика «безопасности», так, что, если в момент, когда все 20 процессов были заняты, поступал 21-й запрос, этот последний должен был ожидать освобождения потока в течение 5 секунд. Если срок ожидания у этого запроса истекал, сервер отчета считал, что что-то не так и что все 20 потоков зависли. Единственным действием дальше становилась остановка и перезагрузка сервера.

Услышав это, я вернулся к своему столу, чтобы все обдумать. Через несколько минут все встало на свои места. Я проверил свои размышления файлами протоколов и трассировок и сообщил мою гипотезу группе, обслуживающей сервер отчетов.

Причина того, что менеджер нагрузки работал только с одним сервером отчетов, была не в том, что алгоритм распределения нагрузки был ошибочным. Он работал только с одним, поскольку остальные были недоступны. Они все перезапускались. Это было легко проверить, взглянув на временные отметки файлов протокола с серверов отчета и менеджера нагрузки.

Протоколы серверов отчета показывали, что запускалась логика «безопасности». Это подразумевало, что у каждого сервера было по 21 конкурирующему процессу. Это означало, что в некоторый момент времени к системе поступило 84 запроса, поскольку к моменту инцидента работали 4 сервера отчетов.

В конечном итоге один из серверов перезапускался из-за запуска логики «безопасности». Это в результате снижало пропускную способность системы до 63 запросов. Однако скорость поступления запросов оставалась постоянной. Это еще увеличивало нагрузку на оставшиеся 3 сервера, и в конечном итоге другой сервер перезапускался из-за логики «безопасности». Пропускная способность падала до 42 запросов. К тому времени, когда первый сервер заканчивал перезагрузку, останавливался и начинал перезапуск третий. Этот эффект мог сохраняться сколь угодно долго, если ничего не менялось, и скорость поступления запросов и скорость ответа оставались постоянными.
Эта гипотеза соответствовала наблюдениям, что сервера перезапускались последовательно, и тому, что они просто не были способны оставаться функциональными. Однако нам еще следовало определить причину перегрузки 84 запросами. Мы уже проверяли, что нагрузка не была чрезвычайно высокой. Оставалась только одна возможность. Проблема должна была быть связана с допущением того, что каждый запрос обрабатывается за 1-2 секунды и что 21-й запрос должен подождать только 5 секунд. Это выбранное значение, по-видимому, было ошибочно. Это допущение является верным в нормальных условиях работы. В начале этого описания я сказал, что сервер при генерации отчета зависит от базы данных. В данном случае база данных претерпевала что-то вроде деградации (meltdown). Мы так и не смогли определить причины такой деградации. Простая команда SELECT вместо десятых долей секунды занимала до 10 секунд. Сильное падение производительности базы данных проявило ошибку проектирования системы, и ситуация быстро ухудшалась. Поскольку каждый сервер отчета, который останавливался, снижал общую пропускную способность, большая нагрузка оказывалась на оставшиеся рабочие сервера. Если не вмешиваться, то проблема просто бы исчезла, когда нагрузка упала бы до величин, меньших 20 одновременно обрабатываемых запросов ко всей системе.

Как только было определено, что сервер базы данных работает неверно, перезагрузка SQL сервера решила проблему.

История: компания Х
В середине 2000 года я начал работать в другой Интернет-компании, которая занималась картографической и деловой информацией, а также электронной коммерцией. Назовем ее Компанией Х. Системная инфраструктура в Компании Х была сходна с инфраструктурой в Компании Y: Web-сервера обращались к менеджерам нагрузки, которые обращались к агентам баз данных, которые и связывались с базами. Однако существовало небольшое усложнение в том, что Компания Х предоставляла интерфейс интерактивного голосового ответа (Interactive Voice Response, IVR), который позволял клиентам осуществлять доступ к системе через обычный телефон. Инфраструктура, которая реализовывала IVR, просто замещала Web-сервер IVR-сервером, который связывался с менеджером нагрузки таким же образом, как и Web-сервера. Другое отличие состояло в том, что Компания Х задействовала два отдельных центра данных. Обычно IVR-сервер использовал один центр в качестве первичной и активной системы. Когда возникали сложности с активным центром, IVR-сервер переключался на другой, запасной центр.
Однажды руководитель технического отдела Компании Х пришел, чтобы попросить меня поговорить с группой, обслуживающей IVR-сервер, и помочь им исследовать недавний выход службы из строя. Несколькими днями ранее работа IVR-системы была нарушена более чем на восемь часов. Когда я пришел поговорить с группой, выяснилось, что для продолжения работы информации очень мало. Были файлы протокола с IVR-сервера на момент выхода его из строя, но они были удалены из-за проблем коммуникации с Центром сетевых операций. Люди, занимавшиеся обслуживанием системы, подозревали, что ошибка была связана с какой-то малопонятной сетевой проблемой центра данных. Однако это не объясняло, почему не использовался запасной центр. После дальнейших исследований оказалось, что проблема в IVR-сервере возникала при соединении с одним из центров данных. Эта проблема сохранялась в течение двух месяцев.

Поскольку я был не знаком с системой, я попросил показать мне сгенерированные файлы протоколов. Я хотел быть способным зафиксировать поведение системы, когда (и если) сбой возникнет опять. Файл протокола, хотя и полезный для просмотра ошибок, не очень помогает в описании действий системы. Он только отображает статус каждого запроса, после того как он был обработан. Если бы какой-нибудь запрос вызвал ошибку, файл протокола никогда не показал бы состояние IVR-сервера в момент сбоя. Более того, IVR-сервер не выходил из строя при сбое системы. Не было ни одного базового файла, который можно было бы использовать. Однако файл протокола показывал относительно большое число событий при переключении IVR-сервера от одного центра данных к другому. Каждое событие переключения центров данных имело корреляцию с серией из трех запросов со статусом кода ошибки -3, кода, который означал, что время ожидания у запроса истекло, когда IVR-сервер пытался соединиться с менеджером нагрузки. В Компании Х каждый запрос имел уникальный идентификатор (ID), который заносился в файл протокола на любом сервере, к которому этот запрос обращался, так что была возможность проследить путь запроса в системе. Однако IVR-сервер не записывал ID запроса в свой протокол, так что мы не могли выяснить, почему истекло время ожидания.

Наученный опытом, полученным в Компании Y, я спросил о стратегии преодоления ошибок на IVR-сервере. Оказалось, что IVR имеет требования к быстродействию - в отличие от использования Web-сайтов, при использовании телефона люди не любят ждать. Поэтому IVR должен ответить в течение определенного времени. IVR-сервер должен был получить данные от менеджера нагрузки в течение трех секунд. После трех последовательных, закончившихся неудачей попыток сервер автоматически переключался на запасной центр данных. Оставаясь соединенным с запасным центром данных, IVR-сервер через 2 часа пытался восстановить соединение с первичным центром данных. Если попытка оказывалась успешной, сервер вновь переключался на первичный центр данных.

К этому времени у меня были две довольно разумные гипотезы, которые объясняли все наблюдения. (1) Поскольку проблемы на IVR-сервере были при соединении с одним из центров данных, по всей видимости, IVR-сервер работал без резерва. Если бы на центре данных, к которому он был подключен, возникли проблемы, служба IVR оказалась бы недоступной. И (2) причина того, что IVR-сервер не мог поддерживать соединение с центром данных, была точно записана в существующем файле протокола. Это было истечение времени ожидания его запросов. Чтобы определить, почему время ожидания заканчивается так часто, нам следовало проследить путь запросов, которые вызывали его.

Не было, однако, протоколов или другой информации, чтобы проверить мои гипотезы, поэтому я совместно с командой обслуживания IVR-сервера начал работу по генерации более полезного протокола. Как только мы оказались способны проследить поток запросов через систему, сразу стало видно, где здесь узкое место. Один из серверов базы данных тратил необычно долгое время на обработку запросов. Этот сервер делал несколько SQL запросов к базе данных, которая располагалась на той же машине, что и сам сервер. Продолжительность вызовов была существенно выше, чем ожидалось. Поскольку на сервере базы данных была видна необычно высокая загрузка процессора, было сделано предположение, что машина слишком перегружена и, возможно, необходимо дополнительное оборудование. Другая гипотеза состояла в том, что SQL-операторы, как они были реализованы, являлись неэффективными. Это необходимо было проверить. Еще несколько дней исследований выявили, что база данных обновлялась за 2 месяца до инцидента. Однако администратор базы данных забыл переиндексировать базу, и каждый запрос занимал в 10 раз больше времени на обработку, чем обычно. Сильная нагрузка на процессор просто отражала выполнение SQL-операторов на неиндексированной базе. База на «рабочем» центре данных была обновлена и переиндексирована, поэтому никаких неприятностей не возникло. Мы никогда бы не смогли правильно объяснить причины сбоя, поскольку не было информации для исследований. Однако главной причиной сбоя было отсутствие запасного сервера данных.

Выводы

0

11

Выводы
Сходство между предыдущими двумя случаями поразительно. В обоих случаях участвовали системы, которые были работоспособными долгое время. Обе системы работали как положено и не содержали ошибок реализации. Устранение проблемы в обоих случаях (по крайней мере, быстрое) состояло просто в перезапуске или переиндексировании базы данных. Обе проблемы проявились, поскольку ответы баз данных занимали больше времени, чем ожидалось. Причины проблем были хорошо видны в файлах протокола. Однако было трудно отследить в файлах и понять эти причины. Почему?

Компонентное мышление. - В обоих случаях инженеры концентрировались главным образом на компонентах. Они никогда не рассматривали наблюдения в контексте целой системы. Наладка в распределенной компьютерной среде требует целостного подхода. Каждый компонент системы может влиять на поведение другого компонента и системы в целом. Взаимосвязи между компонентами могут быть очень сложными и часто непонятными интуитивно. Когда вы интересуетесь, почему компонент вышел из строя, может быть, полезно задать вопрос: «Какой другой компонент системы мог вызвать сбой этого компонента?»

Ориентировка по вторичным признакам. - Несколько лет назад я участвовал в занятиях по лавинной безопасности. Одной темой этих занятий было проведение поиска с помощью радиомаяков. Идея такого поиска заключалась в том, что, если жертву засыпало снегом, ее радиомаяк посылал радиосигнал, который приемник на другом радиомаяке мог принять. В приемнике радиосигнал преобразовывался в звуковой сигнал. Чем громче был звук, тем ближе была жертва. Первоначально у меня были проблемы с поиском. Вместо того чтобы слушать звуковой сигнал и следовать по нему, я искал видимые признаки. Как только мне удалось отбросить все мои прочие чувства и сфокусироваться на звуке, спасение жертвы у меня существенно ускорилось. Тот же самый совет будет полезен при наладке приложений. В обоих наших примерах инженеры игнорировали подсказки, которые давали им их системы. Вместо того чтобы следовать этим подсказкам, они выбрали ориентировку по вторичным признакам и создавали некорректные гипотезы, не объяснявшие всех наблюдений. Все подсказки и все наблюдения нужно принять во внимание при создании гипотезы.

Игнорирование подсказок. - Важные подсказки игнорировались. В компании Х повышенную нагрузку на процессор у сервера базы данных нужно было исследовать, поскольку скорость поступления запросов не превышала нормальной. Неприемлемое время вызова и обработки запроса у сервера базы записывались в файлы протокола в течение двух месяцев, пока проблема сохранялась. Было множество предупреждений, что нечто плохое потенциально может случиться. Однако из-за недостатка времени, ресурсов и инфраструктуры на эти предупреждения не обращали внимания, пока не случилась катастрофа.
В этих двух инцидентах не были задействованы программные ошибки в традиционном смысле этого слова, хотя даже разработчики были поставлены в тупик. Проблемы, с которыми столкнулись Компании Х и Y, можно было предотвратить, если бы обслуживающий персонал был лучше информирован. Каким образом?

Лучшие инструменты мониторинга. - В обоих случаях, если бы обслуживающий персонал смог обнаружить и зафиксировать необычное поведение сервера базы данных, возможно, они смогли бы предпринять действия для корректировки сервера базы данных. Проблемы, с которыми мы столкнулись, могли бы никогда не проявиться.

Следование правилам. - В Компании Х существовало стандартное правило переиндексировать базу данных после ее обновления. В данном случае переиндексирование не было произведено и не было никаких записей об обновлении.
Недостаток записей сделал трудным определение изменений в окружении и в системе для нужд наладки.

Therac-25
Ошибка аппарата Therac-25 была, пожалуй, самой дорогой ошибкой в современной истории. Как известно, с июня 1985 по январь 1987 года шесть пациентов получили передозировку радиации, что привело к гибели троих из них. Здесь мы полностью полагаемся на отчет, опубликованный Leveson и Turner в 1993 году после нескольких лет расследования. Этот отчет содержит наиболее тщательную и детальную оценку причин и следствий инцидента с Therac-25 и охватывает все аспекты безопасности системы. Однако, поскольку наша книга посвящена программным ошибкам, мы ограничим наше изложение и анализ результатами, связанными с программным обеспечением6.
История
Therac-25 представлял собой компьютеризированную машину для радиационной терапии, построенную компанией Atomic Energy of Canada Limited (AECL). Предшественниками Therac-25 были Therac-6, который представлял собой ускоритель на 6 миллионов электрон-вольт (МэВ), способный испускать только рентгеновские лучи, и Therac-20, рентгеновский излучатель и ускоритель электронов на 20 МэВ. Все три машины использовали мини-компьютер DEC PDP-11. И в Therac-6, и в Therac-20 использовались некоторые аппаратные возможности для предотвращения небезопасных операций. Некоторые программные модули из Therac-6 были использованы вновь в Therac-20 и Therac-25. Кроме того, в Therac-25 были использованы программные модули Therac-20 для электронного режима.
Therac-25 был усовершенствованием Therac-20. Он был способен испускать фотоны или электроны с энергией 25 МэВ с возможностью переключения уровней. Он был меньше, имел больше возможностей и был легче в использовании. Также он был сконструирован так, чтобы компьютерное управление было более полным, чем в его предшественниках. Программное обеспечение, разработанное для Therac-25, было способно осуществлять контроль состояния и управление оборудованием. Поэтому решено было удалить аппаратные средства безопасности и полагаться в этом вопросе на программное обеспечение.

Therac-25 поступил в продажу в конце 1982 года, и 11 таких машин были установлены в Северной Америке, 5 - в США и 6 - в Канаде. Шесть несчастных случаев с большими передозировками произошли между 1985 и 1987 годами7.

Kennestone Regional Oncologyl Center, г. Кенстоун, округ Мариетта, штат Джорджия (Kennestone, Marietta, Georgia). Июнь 1985
Женщина в возрасте 61 года была направлена в онкологический центр для дополнительного лечения аппаратом Therac-25 после хирургического удаления молочной железы. Как считается, пациентка получила одну или две дозы радиации от 15 000 до 20 000 рад (поглощенная доза радиации). Для сравнения, типичная разовая терапевтическая доза радиации составляет до 200 рад. Кенстоунская клиника использовала Therac-25 с 1983 года без происшествий. Техники и фирма AECL не поверили, что эта проблема может быть вызвана Therac-25. В конечном итоге пациентка потеряла грудь, а также возможность пользоваться руками и плечами из-за радиационного поражения.

Ontario Cancer Foundation, Хемилтон, провинция Онтарио, Канада (Hamilton, Ontario, Canada)
Клиника в Хэмилтоне использовала Therac-25 в течение шести месяцев до инцидента с передозировкой. Сорокалетняя женщина поступила в клинику на 24-й сеанс лечения аппаратом Therac-25. Аппарат отключился через пять секунд после того, как оператор запустил его. Операторы были знакомы с частыми неполадками машины. Эти неполадки, вероятно, не имели серьезных последствий для пациента. Поскольку машина показывала, что облучение не было произведено, оператор попытался повторить его. Были произведены пять попыток. После пятой попытки был вызван техник, не обнаруживший проблем в аппарате.

Об инциденте сообщили в AECL, но воспроизвести неполадку и сделать заключение о причинах такого поведения Therac-25 не удалось. Однако благодаря этому сообщению фирма AECL обнаружила некоторые слабости конструкции и потенциальные механические проблемы в позиционировании поворотной платформы Therac-25 и были сделаны исправления. Пациентка умерла через пять месяцев. Результаты вскрытия показали, что смерть наступила от рака, а не от передозировки радиации. Однако вскрытие также выявило серьезные поражения бедра, вызванные радиационным воздействием. Как было позже определено, пациентка получила дозу порядка 13 000 - 17 000 рад8.

Yakima Valley Memorial Hospital, Якима, штат Вашингтон (Yakima, Washington). Декабрь 1985
После лечения аппаратом Therac-25 у женщины развилось сильное покраснение кожи в форме параллельных полос. Персонал клиники считал, что это явление мог вызвать Therac-25. Однако они не смогли воспроизвести конфигурацию оборудования, которая была использована при лечении пациентки. Персонал проинформировал AECL о потенциальной передозировке. В AECL снова посчитали, что передозировка при использовании аппарата Therac-25 невозможна. Персонал клиники не был осведомлен о двух предыдущих случаях и не имел возможности расследовать инцидент, поэтому они не стали продолжать дело после ответа из AECL. Пациентка, вероятно, получила более низкую дозу радиации, чем два предыдущих пострадавших, и она не испытала серьезных последствий в результате передозировки9 .

East Texas Cancer Center (Восточно-техасский онкологический центр), г. Тайлер, штат Техас (Tyler, Texas). Март 1986
Восточно-техасский онкологический центр использовал аппарат Therac-25 с 1984 года и применял его при лечении более 500 пациентов. 21 марта 1986 года пациент (мужчина) был направлен на дополнительное лечение. Оператор, которая осуществляла лечение, была знакома с Therac-25 и хорошо разбиралась в его свойствах и в процессе использования. Когда она вводила данные пациента и врачебные предписания, она допустила ошибку, которую быстро исправила и начала лечение. Спустя мгновение машина отключилась, и дисплей отобразил сообщения об ошибках. Как обычно происходит в программных системах, сообщение об ошибке представляло собой код, который никто не смог бы расшифровать. «Ошибка 54» расшифровывалась в печатном перечне ошибок как «ввод дозы 2». Восточно-техасский онкологический центр не располагал другой документацией, которая объясняла бы смысл выражения «ввод дозы 2». Дисплей показал также очень малую дозу облучения и, поскольку оператор была знакома с капризами Therac-25, она немедленно запустила повторное лечение. Машина снова отключилась с теми же сообщениями об ошибках.

Клиника связалась с AECL по поводу этой проблемы. Техники фирмы, направленные в Восточно-техасский онкологический центр, не смогли воспроизвести неисправность, и AECL все так же считала, что передозировка на Therac 25 невозможна. Пациент умер от осложнений передозировки через пять месяцев после этих событий10 .

East Texas Cancer Center (Восточно-техасский онкологический центр), г. Тайлер, штат Техас (Tyler, Texas). Апрель 1986
Три недели спустя другой мужчина поступил для лечения с помощью Therac 25. Та же женщина-оператор, которая участвовала в прошлом инциденте, была ответственной за лечение. Как и в предыдущем случае, она сделала ошибку при вводе данных, и, почти столь же быстро исправив ошибку, она запустила лечение. Машина ответила сообщением «ошибка 54» и отключилась. Однако пациент уже получил передозировку, и оператор побежала за помощью. Therac-25 был отключен, и клиника проинформировала AECL о втором случае передозировки.

Физик клиники, Фриц Хэгер (Fritz Hager), совместно с оператором научились воспроизводить сообщение «ошибка 54» произвольно. Оказалось, что передозировка возникала, если данные врачебного предписания редактировались в быстром темпе. Люди из AECL наконец смогли воспроизвести ошибку и признали, что передозировка была возможна11.

Как же было возможно, что быстрое редактирование вызывало передозировку? Аппарат Therac-25 мог работать в одном из двух режимов - фотонном или электронном. В электронном режиме оператору было необходимо ввести уровень энергии. Если же был выбран фотонный режим, по умолчанию энергия фотонов принималась за 25 МеV. Ошибки, совершенные оператором в обоих случаях, были одни и те же. Для двоих пациентов, которые получили передозировку, требовался электронный режим. Однако, поскольку большинству пациентов нужен фотонный режим, оператор привыкла выбирать последний. В этих двух случаях оператор первоначально выбирала фотонный режим, а затем исправляла свою ошибку. Физическая калибровка и настройка магнитов занимает около 6 секунд. Программный модуль, который проверяет завершение ввода данных, должен произвести калибровку магнитов, как только были установлены параметры режима и уровня энергии. Другой программный модуль был ответственен за проверку изменения входных данных. Если изменения были произведены, настройка магнита сбрасывалась и калибровка начиналась заново с новыми параметрами. Однако логическая ошибка в этом модуле вызывала то, что он был не способен распознать изменения данных, если они производились в течение восьми секунд после того, как были введены первоначально. (Это чрезвычайно упрощенное описание программного алгоритма. Советую читателю обратиться к отчету Levenson and Clark за дополнительными подробностями.) В этих двух случаях, когда оператор выбирала фотонный режим в первый раз, машина подготавливала к использованию уровень энергии в 25 MeV в фотонном режиме. А когда оператор изменила режим на электронный в течение восьми секунд, параметры магнитов не были сброшены и давалась неверная доза.

Когда в фирме AECL поняли ошибку, фирма немедленно разослала письмо к пользователям, в котором рекомендовала временные меры, заключавшиеся в том, чтобы не редактировать данные в ходе процесса их ввода.

Пациент скончался через три недели после инцидента от передозировки радиации12.

Yakima Valley Memorial Hospital, г. Якима, штат Вашингтон (Yakima, Washington). Январь 1987
К этому времени проблемы с машиной Therac-25 были преданы широкой гласности, по крайней мере в сообществе пользователей. Операторы знали о запрете редактировать данные. В то время когда AECL совместно с Управлением по контролю за продуктами и лекарствами (FDA) активно занималась планом работ по устранению неполадок, случился шестой инцидент. В данном случае пациент должен был получить три дозы облучения. Первые две дозы составляли 4 и 3 рад. Следующая доза составляла 79 рад в фотонном режиме. Первые два сеанса прошли без осложнений. После второй дозы оператор вошел в комнату облучения, чтобы повернуть поворотную платформу, чтобы проверить положение лучевого пучка относительно тела пациента. Оператор нажал кнопку возле поворотной платформы для указания того, что контроль произведен. Установив платформу, оператор запустил процесс лечения. Машина остановилась через 5-6 секунд, и поэтому оператор запустил лечение снова. И снова машина отключилась и отобразила «маловразумительную» причину остановки. Возникло предположение о передозировке, однако дисплей показал только облучение в 7 рад от двух первых сеансов.

Через неделю AECL обнаружила недостаток в программном обеспечении, который смог объяснить это поведение. Этот программный дефект отличался от того, который был обнаружен в Восточно-техасском онкологическом центре в деталях. Однако оба дефекта были вызваны неожиданными зависимостями от скорости в программных модулях. В данном случае существовала разделяемая переменная, названная Class3, содержащая однобайтовое значение. Это значение указывало, соответствуют ли параметры машины параметрам лечения. Если значение Class3 было ненулевым, параметры считались несоответствующими, и пучок лучей подавлялся. Эта переменная инициализировалась в модуле, который готовил машину к лечению. Однако инициализация заканчивалась инкрементированием данной переменной. Поскольку переменная была однобайтовой, через каждые 256 итераций значение ее доходило до нуля, программный модуль, проводивший инициализацию, запускался все время в зависимости от других событий в системе. Если кнопка на поворотной платформе была нажата именно в тот момент, когда переменная Class3 была равна нулю, проверка соответствия не производилась, и машина могла облучить пациента электронным пучком дозой до 25МеV.

Пациент умер в апреле 1987 году от осложнений, вызванных передозировкой. Машина была отозвана вскоре после этого13.

Выводы
За короткую жизнь Therac-25 было обнаружено два программных дефекта:

Логическая ошибка в обновлении параметров, когда оператор менял состояние машины.

Проверка безопасности не срабатывала, когда 8-битный счетчик переполнялся и достигал нуля каждые 256 итераций.
Однако с точки зрения безопасности систем самое уязвимое место - это доверие к программному обеспечению. Очевидно, что тот же дефект, который вызвал передозировки в Therac-25, присутствовал и в Therac-20. Та же ошибка в Therac-20 приводила к отключению машины без передозировки, поскольку в Therac-20 применялись независимые аппаратные устройства безопасности, которые предотвращали ее.

Ошибки, связанные с зависимостью от скорости, очень трудно обнаружить и воспроизвести. В первом случае две причины точно должны были присутствовать, чтобы активировать ошибку.

Оператор должен сделать изменения в параметрах режима и уровня энергии.

Оператор должен сделать изменения в течение восьми секунд.
В случае второго дефекта все зависит от случайности. Ошибка активируется, если клавиша нажимается в тот момент, когда счетчик достигает нуля. Вот почему, несмотря на врожденный дефект в продукте, было отмечено только шесть несчастных случаев. Если бы ошибка была более явной и ее было бы легче запустить, несомненно, она была бы выявлена на AECL в ходе обычных процедур тестирования и проверки качества, и тогда о ней никогда не узнало бы общество. Если ошибку трудно активировать, ее также трудно будет выявить в ходе обычного процесса тестирования. Трудно найти ошибки, если не можешь их воспроизвести.

Замечание     Большинство аварий - аварии системные, то есть они происходят в результате сложных взаимодействий между различными компонентами и процессами. Приписывать аварии какой-либо одной причине - обычно серьезное заблуждение.14 

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

Аппарат Therac-25 имел много неполадок, которые, по-видимому, не причиняли вреда, и операторы научились игнорировать эти капризы. Это напоминает историю о мальчике, который кричал «волк!». Люди научились не обращать на него внимания. Частые отключения и остановки машины беспокоили операторов. Однако операторы никогда не видели никаких вредных последствий для пациентов из-за этих отключений, поэтому они научились игнорировать их. Нечто, что может иметь серьезные последствия, игнорировалось. Постоянные неполадки также демонстрировали внутреннюю нестабильность и небезопасность машины.

Когда проявлялась неполадка, Therac-25 выдавал непонятные сообщения, которые не давали обслуживающему персоналу никаких ключей к причинам и следствиям системной ошибки. Конструкция системы не предусматривала адекватной обратной связи, и персонал не мог понять, что происходит. Информация проходила от оператора через программное обеспечение к оборудованию. Когда связь нарушалась, пользователь не имел способов узнать состояние оборудования, поскольку построение программ не позволяло опрашивать оборудование. Ошибка при вводе данных ясно показывает последствия недостатка обратной связи. Например, вместо того, чтобы просто позволить оператору включать пучок лучей после изменения параметров, программы могли быть сделаны так, чтобы облучение не могло начаться до тех пор, пока программа не опросит оборудование о его состоянии и не предоставит эту информацию оператору для проверки.

Когда клиники связывались с AECL по поводу потенциальных проблем, фирма не принимала эти проблемы всерьез. Поскольку люди из AECL не могли воспроизвести неисправность, они считали, что проблема не может быть связана с машиной. Более того, поскольку Therac-25 базировался на Therac-20 и Therac-6, машинах, прошедших полевые испытания, они были слишком самоуверенны в отношении потенциального риска. Ошибки были трудны для обнаружения, но, проявив достаточно внимания, их можно было найти. Инциденты в г. Якима 1985 и 1987 годов являются тому яркими примерами. Когда о проблеме впервые сообщили в 1985 году, фирма AECL провела только поверхностное расследование. Она сообщила, что ошибка невоспроизводима и, следовательно, проблемы нет. Однако в 1987 году фирма приняла сообщение всерьез и обнаружила возможную причину некорректного поведения в течение нескольких недель. Как только AECL оказалась готова признать, что ее продукт может содержать дефекты, она оказалась способна взглянуть на проблему с другой точки зрения.

Когда была обнаружена ошибка ввода данных, видимо, не было сделано ни единой попытки оценить безопасность системы в целом. В то время поступили сообщения о пяти случаях, а ошибка ввода данных могла объяснить только два из них - случаи в Восточно-техасском онкологическом центре. Первые три передозировки нельзя объяснить этой ошибкой. Это указывает на то, что в системе были другие дефекты, не принятые в расчет, и машина, по-видимому, могла и далее передозировать облучение по другим причинам. Через восемь месяцев произошел второй случай в г. Якима.

В Therac-25 было вновь использовано программное обеспечение его предшественников. Повторное использование программ позволило фирме AECL быстрее вывести Therac-25 на рынок, но внушило им ложную самоуверенность по поводу запаса прочности системы. Повторное использование программ приветствуется ведущими специалистами в индустрии в качестве пути к повышению продуктивности и снижению числа дефектов. Это так, но, с другой стороны, это означает, что программные ошибки воспроизводятся. Кроме того, повторное использование создает новые взаимодействия между ранее не связанными компонентами в новом окружении. Эти взаимодействия могут проявить скрытые дефекты и сформировать новые. Дефект, который не проявляет себя в одном случае, может внезапно возникнуть в другой среде. Также, программы обычно плохо документируются, и пользователям трудно понять нюансы повторного использования программных модулей. Массированное использование таких модулей может также привести к неудобному и небезопасному дизайну.
Зарисовка #1
В апреле 2000 года секретный девятистраничный документ НАТО, датированный 23 сентября 1999 года, попал в одну лондонскую издательскую фирму. В ходе Косовского конфликта компьютеры НАТО подвергались атакам со стороны сербов. Ученые НАТО, в поисках путей защиты от дальнейших вирусных атак, создавали вирусы для моделирования различных режимов атаки. Однако эксперимент пошел не так, как планировалось. Экспериментальные вирусы сделали в точности то, что и должны были сделать. Они извлекли документы с жестких дисков инфицированного компьютера и разослали их в качестве невидимых приложений к электронной почте. Так были разосланы секретные документы15.
Ошибка в данном случае представляла собой не вирус, разработанный и реализованный специалистами НАТО. Ошибки были в сетевом окружении и процессе тестирования, которые и позволили разослать секретные материалы. Разве вам не нравится, когда компьютер делает то, что вы от него требуете?

Ошибка в процессоре Intel Pentium
В 1993 году корпорация Intel представила новый процессор Pentium™, который обещал стать самым лучшим процессором на рынке персональных компьютеров в то время. Через год после выпуска профессор Томас Найсели (Thomas Nicely) из Линчбергского колледжа (Lynchburg College) обнаружил ошибку и сообщил о ней в Intel. Это стало совершенным кошмаром для Intel, и в конечном итоге фирма согласилась заменять микросхему автоматически по требованию. Популярная пресса заставила нас поверить, что эта ошибка вызвана глупостью инженеров Intel, - в конце концов, разве трудно проверить каждое значение по справочной таблице? Как обычно, реальность намного сложнее, чем жирные заголовки газетных статей.

0

12

История
Профессор Томас Найсели - математик. В период 1993-1994 годов он работал над исследовательским проектом в области, называемой вычислительной теорией чисел (computational number theory). Одной из его целей было продемонстрировать полезность настольных персональных компьютеров. Для своего исследования он заставил большое число персональных компьютеров вычислять простые числа, пары простых чисел, триплеты и квадраплеты простых чисел для всех положительных целых до 6 x 1012. Простые числа - это целые, которые делятся только на единицу и сами на себя (например, 3). Пары простых чисел - это два последовательных нечетных целых, которые также являются простыми (например, 3 и 5). Триплеты простых - это три последовательных целых нечетных простых числа (3, 5, 7). При вычислениях его программа предпринимала некоторое число проверок, в которых уже известные, опубликованные в литературе числа просчитывались, чтобы проверить правильность вычислений. Машина с процессором Pentium приняла участие в вычислениях в марте 1994, а 13 июня 1994 года проверка закончилась неожиданным значением. После четырех месяцев поиска профессор Найсели смог определить ошибку в блоке вычисления чисел с плавающей запятой (floating-point unit, FPU) процессора Pentium. В публичном сообщении, сделанном 9 декабря 1994 года, он описал свои трудности и исследования причины ошибок16.
24 октября 1994 года, после того как профессор окончательно уверился в результатах анализа, он послал в службу технической поддержки Intel сообщение об ошибке. Когда Intel не ответила на сообщение, 30 октября 1994 года профессор Найсели написал письмо некоторым своим коллегам, объявив об открытии ошибки деления чисел с плавающей запятой в процессоре Intel Pentium. В электронном письме он описал свои наблюдения:

Если коротко, FPU процессора Pentium возвращает ошибочное значение для некоторых операций деления. Например,

     1/824633702441,0

вычисляется некорректно (ошибочны все цифры после восьмой значащей цифры)17.

Вскоре сообщение об ошибке уже циркулировало на форуме CompuServe и в группах новостей Интернета. Александр Вулф (Alexander Wolf), репортер EE Times, подхватил эту историю и написал статью, которая появилась в номере EE Times от 7 ноября 1994 года. Отвечая на запрос репортера, Intel заявила, что они обнаружили эту ошибку летом 1994 года, и она была исправлена в процессорах, выпущенных позднее. Однако Intel не смогла определить число выпущенных дефектных процессоров, и они попытались сгладить важность этой ошибки.

Смит (Smith), представитель Intel, подчеркнул, что этот дефект не повлияет на среднего пользователя. Говоря о Найсели, Смит сказал: «Это исключительный пользователь. Он круглосуточно проводит вычисления обратных величин. То, что он обнаружил после многих месяцев вычислений, является примером того, что восемь десятичных чисел правильны и только девятая отображается неверно. То есть ошибка у вас будет только в девятом знаке справа от точки. Я думаю, что, даже если вы инженер, вы этого не заметите».18

CNN распространила это заявление 22 ноября 1994 года, и вскоре оно было во всех главных средствах массовой информации, таких, как New York Times и Associated Press. В других интервью Intel повторяла свое раннее заявление о том, что ошибка несущественна для среднего пользователя.

В среду Intel заявила, что они не считают необходимым отзывать процессор, утверждая, что обычный пользователь имеет только один шанс из девяти миллиардов получить неверный результат из-за этой ошибки и таким образом не будет никаких заметных последствий для компьютеров дома и в офисе. Компания заявляет, что она продолжает поставлять сборщикам компьютеров процессоры Pentium, сделанные до того, как проблема была обнаружена19 .

28 ноября 1994 года Тим Коу (Tim Coe) из компании Vitess Semiconductor опубликовал статью в группе новостей comp.sys.intel, в которой он путем анализа восстановил реализацию алгоритма и предложил модель поведения процессора Pentium. Через несколько дней появились аппаратные и программные «заплатки» для ошибки. 3 декабря 1994 года Воэн Пратт (Vaughan R. Pratt) из Стэндфордского университета опубликовал письмо в группах новостей comp.arch и comp.sys.intel, в котором оспаривал точку зрения Intel о том, что вероятность встречи с ошибкой составляет «один раз в 27 000 лет». Он смог продемонстрировать возможность активации ошибки один раз в каждые 3 миллисекунды в достаточно правдоподобном сценарии. А также он продемонстрировал, что достаточно безобидно выглядящее деление 4,999999/14,999999 приводило к отклонению от правильного результата на 0,00000407 при использовании дефектного процессора20.

12 декабря 1994 года фирма IBM выпустила сообщение, в котором также был подвергнут сомнению анализ Intel о том, что вероятность обнаружения ошибки составляет один к девяти миллионам21.

14 декабря 1994 года Intel опубликовала официальное сообщение, которое было датировано 30 ноября 1994 года22.

В этом сообщении рассматривалась данная ошибка, обсуждались ее последствия, и этот документ был, очевидно, источником многих заявлений Intel. В этом отчете определялось, что вероятность встречи с ошибкой составляет «один к девяти миллиардам» и что среднее время появления ошибки - «один раз в 27 000 лет». Далее Intel описывала причину ошибки и алгоритм работы FPU. Инженеры компании избрали в качестве алгоритма деления процессора SRT алгоритм23 по основанию 4 (radix 4 SRT algorithm), чтобы скорость деления могла быть удвоена, по сравнению с 486-м процессором. Полное описание SRT алгоритма, использованного в процессоре Pentium, находится за рамками этой книги. Детали можно найти в работе Edelman, Sharangpani и Bryant24.

Однако главная причина ошибки в том, что SRT-алгоритм требует справочную таблицу для определения частного. Значение в справочной таблице генерируется численно и загружается в программируемый справочный массив. Дефект скрипта привел к тому, что несколько элементов в справочной таблице были пропущены. Когда выполнялась операция деления, которая требовала эти значения, извлекалось неверное число, и точность вычисленного результата частного оказывалась сниженной.

В конечном счете 20 декабря 1994 года фирма Intel объявила, что она начинает заменять процессоры Pentium по требованию. Это существенно снизило ажиотаж вокруг ошибки в процессоре. Однако это не остановило тех, кто анализировал эту ошибку. 19 сентября 1995 года Алан Эдельман (Alan Edelman) опубликовал отчет, в котором провел детальный анализ этой ошибки25.

В своем отчете он определил, что было только два способа, с помощью которых можно было осуществить доступ к ошибочным данным и использовать их при вычислениях. Ошибочное значение извлекалось, только если делитель содержал шесть последовательных бит, от 5-го до 10-го, установленных в единицу. Таким образом, ошибочные табличные значения могли не извлекаться при тестах, основанных на случайной выборке значения; тест, способный выявить ошибку, должен работать лучше, чем простая случайная выборка. Он также показал, что максимальная абсолютная ошибка в данном случае не могла превышать 0,00005.

Вывод
Ошибка в процессоре Pentium - это ошибка, которую легко совершить, но которую трудно обнаружить в силу двух причин. Во-первых, ошибка в результате операции деления, проведенной дефектным процессором, не превышает 0,00005. Как много из нас придрались бы к различию между 0,33332922 и 0,33333329? Более того, если бы мы использовали эти значения в приложениях, которые автоматически округляют их до двух значащих цифр, мы бы никогда и не узнали о таких небольших различиях. Воэн Пратт писал в своем сообщении:
Эта ошибка наиболее коварна: она почти столь же коварна, как если бы вовсе не вызывала тревоги у людей при просмотре ими колонок своих данных. Таким образом, крошечные ошибки в одну стотысячную могут в течение долгого времени проникать в триллионы вычислений, совершаемых по всему миру, и практически нет способа определить их, кроме как осуществляя массированную проверку на ошибку в FPU, которая совершенно не является необходимой для надежно работающего процессора26.
Вторая причина того, что ошибку трудно найти, состоит в том, что дефект проявляется чрезвычайно редко27.
Шанс того, что неверное значение будет извлечено из справочной таблицы в тестах по случайной выборке, чрезвычайно низок. Intel, используя эти тесты, независимо от других идентифицировала ошибку через год после выпуска процессора. Это ясно говорит о трудностях тестирования и обнаружения этого дефекта.

Для профессора Найсели процесс поиска ошибки начался, поскольку он заметил небольшие несоответствия. Но причина того, что он оказался в состоянии заметить несоответствия, состоит в том, что он поместил операцию проверки вычислений в свой код. Без этих проверок он мог и не заметить проблему так рано, и его вычисления простых чисел могли быть ошибочными. Как только он понял, что проблема существует, он начал систематически убирать ее возможные причины, пока поиск не сузился до FPU процессора Pentium.

Уроков, которые мы можем извлечь за счет Intel, довольно много:

Тестирование должно не только следовать спецификации, оно для полноты также должно учитывать использованные алгоритмы.

Мы должны использовать в программах средства для постоянного контроля над правильностью программы. Это даст нам возможность найти потенциальные ошибки настолько рано, насколько возможно.

Все неожиданные результаты нужно ставить под сомнение и проверять до тех пор, пока мы не объясним их причину. Ошибка может оказаться скрытой.

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

Создание упрощенного воспроизводимого опыта может все изменить. Тот факт, что профессор Найсели смог активировать ошибку простой операцией деления, позволил ему протестировать другие системы и конфигурации, что позволило ему опровергнуть неверные гипотезы.
Зарисовка #2
Согласно легенде, ранние конструкции торпед имели устройства безопасности, предохраняющие подводную лодку от повреждения, когда торпеда была запущена. Торпеда была сконструирована так, чтобы самоуничтожение запускалось, если торпеда поворачивалась на 180? . Идея была в том, что повернувшаяся на 180? торпеда может повредить выпустившую ее лодку. Однажды, капитан подводной лодки решил выпустить торпеду. Однако торпеда застряла в пусковой камере, и ее не смогли удалить. Капитан решил вернуться в порт для ремонта. Когда субмарина развернулась на 180 градусов, торпеда взорвалась и потопила лодку.
В данном случае ошибка заключалась в конструкции торпеды. Когда-то кто-то решил, что неплохо было бы встроить в торпеду некий предохранитель так, чтобы она не смогла потопить запустившую ее лодку. Идея была хорошей, а вот ее реализация - нет. Конструктор не учел тот самый случай, который и потопил субмарину. Однако остается неясным, на самом ли деле на заре конструирования вооружения для субмарин такой случай произошел или это всего лишь легенда. Но он показался нам достаточно реалистичным и поучительным, так что мы решили его привести.

Ariane 5. Ошибка операнда
Если коротко, несчастный случай с Arian 5 был вызван необработанным исключением при преобразовании 64-битного значения с плавающей запятой в 16 битное целое значение со знаком. Значение с плавающей запятой, вызвавшее исключение (или ошибку операнда, как она была названа в официальном сообщении), оказалось больше, чем значение, которое может быть представлено 16 битным целым. Однако более полная версия этой истории гораздо более интересна и поучительна28.
История
Ракета-носитель Ariane 5 была ответом попыткам Европейского космического агентства (European Space Agency) стать лидером в запусках ракет на коммерческом космическом рынке. Стоившая 7 миллиардов долларов и строившаяся в течение 10 лет, Arian 5 могла вывести на орбиту два трехтонных спутника.
При своем первом полете ракета Ariane 5 взорвалась через 40 секунд после старта утром 4 июня 1996 года. Анализ данных полета быстро показал, что ракета вела себя нормально до того момента, когда она вдруг отклонилась от курса и самоуничтожилась. Погода в то утро была приемлемой, так что она не могла оказать влияние. Полетные данные также показывали, что активная система и первичная Инерционная система ориентировки (Inertial Reference System), которые влияли на управление соплами твердотопливного ускорителя, более или менее одновременно отказали прямо перед разрушением ракеты.

После инцидента была сформирована комиссия по его расследованию. Комиссия для решения своей задачи располагала телеметрическими данными ракеты, данными о траектории с радиолокационных станций, оптическими наблюдениями ракеты и упавших обломков и восстановленной Инерционной системой ориентировки. Кроме того, комиссия располагала отдельными компонентами ракеты и системами программ, использованных в ней, для тестирований и осмотра. Получив эту информацию, комиссия смогла реконструировать последовательность событий 4 июня 1996 года.

Программный модуль, в котором в итоге возникла ошибка, был унаследован от ракеты-носителя Arian 4. Этот модуль производил выравнивание инерционной платформы для того, чтобы оценить точность измерений, проведенных Инерционной системой ориентировки. После старта данный модуль более не служил в Ariane 5 никаким целям. Однако в Ariane 4 этот модуль работал в течение еще полных 50 секунд. Начальная часть траектории полета Ariane 5 существенно отличалась от траектории Ariane 4, и этот программный модуль никогда соответствующим образом не тестировался.

Вскоре после старта ошибочный программный модуль попытался посчитать значение, основанное на горизонтальной скорости ракеты. Поскольку для Ariane 5 это значение было существенно больше, чем то, которое ожидалось для Ariane 4, возникла ошибка и на активной, и на запасной Инерционной системе ориентировки. Допустимость такого преобразования не была проверена, поскольку ожидалось, что такого никогда не случится.

Спецификация обработки ошибок в системе указывала, что контекст ошибок должен быть сохранен в постоянной памяти (ПЗУ) до отключения процессора. После ошибки операнда Инерционная система ориентировки сохранила контекст ошибки, как было установлено. Эти данные были прочитаны бортовым компьютером. На основе этих данных компьютер отдал команду соплам твердотопливного ускорителя и главному двигателю. Команда требовала полного отклонения сопел, что вызвало то, что ракета вышла на запредельную траекторию.

На новой траектории ракета подверглась запредельной аэродинамической нагрузке и начала разрушаться. Стартовые двигатели отделились от ракеты, что запустило ее самоуничтожение.
Несомненно, глупая ошибка, но интересен такой вопрос: как эта ошибка миновала стадию тестирования? В аэрокосмической индустрии обычно строгие стандарты и скрупулезные процессы и процедуры, направленные на проверку безопасности из-за высокой цены ошибок. Комиссия по расследованию задала тот же вопрос, и команда обслуживания Ariane 5 представила следующие объяснения:

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

Команда Ariane 5 решила не включать данные о траектории в функциональные требования для Инерционной системы ориентировки. Следовательно, данные о траектории Ariane 5 не использовались при тестировании.

Из-за физических законов трудно осуществить реалистичный полетный тест Инерционной системы ориентировки. При функциональном имитационном тестировании полетных программ было решено не включать в тест эту систему главным образом по той причине, что она должна быть проверена при тестировании аппаратного уровня, а также потому, что было бы трудно достигнуть необходимой точности при имитационном тестировании, если бы была использована реальная Инерционная система ориентировки.
Вывод
Как и в случае других ошибок, которые мы обсуждали, дефект на Ariane 5 не был вызван одной причиной. В ходе всей разработки и процессов тестирования существовало много стадий, на которых данный дефект мог быть выявлен.

Программный модуль был повторно использован в новой среде, где условия функционирования отличались от требований программного модуля. Эти требования не были пересмотрены.

Система выявила и распознала ошибку. К несчастью, спецификация механизма обработки ошибок была несоответственной и вызвала окончательное разрушение.

Ошибочный модуль никогда должным образом не тестировался в новом окружении - ни на уровне оборудования, ни на уровне системной интеграции. Следовательно, ошибочность разработки и реализации не была обнаружена.
Отчет комиссии по расследованию содержит следующее наблюдение, которое мы считаем очень подходящим для всей индустрии программного обеспечения, а не только для разработчиков программ для Ariane 5.

Главной задачей при разработке Ariane 5 является уклон в сторону уменьшения случайной аварии. …Возникшее исключение, объясняется не случайной аварией, но ошибкой конструкции. Исключение было обнаружено, но обработано неверно, поскольку была принята точка зрения, что программу следует рассматривать как правильную, пока не показано обратное. …Комиссия придерживается противоположной точки зрения, что программное обеспечение нужно считать ошибочным, пока использование признанных в настоящее время наилучшими практических методов не продемонстрирует его правильность29.
Однако одна из причин того, что комиссия по расследованию смогла успешно определить виновного, - в сборе данных измерений, в имитационных средах и в документации. Без метеорологических данных было бы трудно исключить влияние погоды. Без телеметрии и полетных данных было бы трудно определить временные параметры изменения траектории и ошибку Инерционной системы ориентации, что позволило комиссии быстро сузить область потенциальных дефектов. Послеполетные имитационные исследования были проведены с использованием реальных данных о траектории полета Ariane 5, и моделирование точно воспроизвело цепь событий, приведших к аварии системы. Комиссия смогла воспроизвести ошибку!

Зарисовка #3
Интернет - это великий источник информации. К сожалению, слово «великий» не используется здесь как прилагательное, описывающее качество информации. «Великий» обозначает количество информации - слишком большое количество информации, которая при некоторых обстоятельствах нежелательна и которую мы называем спам. В других случаях доступ к некоторым специфическим формам информации, таким, как порнография, намеренно блокируется и подвергается цензуре по различным причинам. В любом случае существует некоторое число инструментов, чья функция - служить в роли фильтров для удаления потенциально нежелательных электронных писем и блокировать запросы к некоторым Web-сайтам. Эти средства могут быть источниками большого раздражения. Например:
Только что услышал сообщение по сетевому радио CBS о том, что футбольные фанаты по всей стране не смогли узнать по Интернету результаты воскресного Суперкубка. Оказалось, что программы-фильтры доступа в Web, установленные на браузерах (например, в некоторых публичных библиотеках), рассматривали «ХХХ» в словах «Суперкубок XXXIV» как ссылку на порносайт30.
В другом примере чрезмерная цензура потенциально оскорбительных слов может сделать вполне безобидное сообщение неразборчивым и забавным. Так Интернет-служба BBC подвергла цензуре такое предложение:

Я надеюсь, вы сохраните пристрастие к острым словечкам, когда я заскочу к вам в класс в субботу в Сканторп, Эссекс. «I hope you still have your appetite for scraps of dickens when I bump into you in class in Scunthorpe, Essex, on Saturday».

Программа превратила его в «I hope you still have your appetite for s****s of dickens when I ***p into you in class in S****horpe, Es***, on Sa****ay»31, 32

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

Я недавно провел обновление (?) MS Office до MS Office 2000, который среди прочих возможностей позволяет устанавливать более 8 фильтров электронной корреспонденции. Я радостно начал запускать все эти возможности, включая фильтрацию почты. Сюрприз! Я обнаружил, что 8-10 важных сообщений, которые все являлись ответами на запросы, посланные на адреса из личной адресной книги, были перенесены в папку для почты-спама. Что же случилось? Я участвовал в благотворительной велосипедной гонке, и мне необходимо было сообщить спонсорам, что мне нужны их деньги. Я выслал им электронные письма с просьбой прислать мне чеки. Конечно, это сообщение содержало, по крайней мере, один знак «$», а также, поскольку я возбудимый человек, содержало, по крайней мере, один двойной восклицательный знак «!!». В конце я просил моего респондента выполнить мою гиперболизированную версию его обещания:
>>Марк, ты не обещал мне 5,000$ или что-то около того?

Мы также встретили здесь волшебную фразу «,000». Недавно замечательные люди из Редмонда33 (Redmond) определили, что, если эти три элемента одновременно присутствуют, значит, вы получили спам. Текущее правило (взятое с их Web-сайта) гласит:

Текст содержит «,000» AND текст содержит «!!» AND текст содержит «$»

Кто бы мог подумать? Даже взглянув на список их фильтров, я далеко не сразу понял, какое правило я нарушил (ОК, иногда я медленно соображаю)34.

Это ошибки программы или ошибки пользователя? Во всех трех случаях программное обеспечение функционирует в точности так, как предписывает алгоритм, и производители не посчитали бы эти случаи за ошибки. Однако иногда действие алгоритма - это не то, что хочет конечный пользователь. Поэтому, как конечные пользователи мы выключаем фильтрующее и противоспамное программное обеспечение или же находим пути обойти неверный алгоритм. В главе 3 мы исследуем природу ошибок, что может помочь нам определить точно, что такое ошибка.

Аппарат для исследования климата Марса
Аппарат для исследования климата Марса (Mars Climate Orbiter) является частью программы Mars Surveyor по изучению и картографированию Марса. Ожидалось, что программа Mars Surveyor продлится в течение 10 лет и в рамках программы будет запускаться одна экспедиция в год. Первыми двумя экспедициями были миссии аппаратов Mars Pathfinder и Mars Global Surveyor в 1996 году. Аппарат Mars Climate Orbiter был запущен 11 декабря 1998 года. Следом за ним был также запущен Mars Polar Lander - 3 января 1999. Оба аппарата были потеряны вскоре после того, как они достигли красной планеты. Эти два космических корабля стоили NASA около 327,6 миллиона долларов, потраченных на их создание и функционирование. Эти аварии заставили NASA пересмотреть свои цели и методы в Марсианской программе, чтобы быть уверенными в успехе будущих миссий. Причину аварии Mars Polar Lander определить все еще нельзя. Однако причина потери Mars Climate Orbiter выяснена, поэтому мы сконцентрируем наше исследование на этом аппарате.

0

13

История
Mars Climate Orbiter был запущен 11 декабря 1998 года с помощью ракеты-носителя Delta 11 с космодрома на мысе Канаверал (Canaveral) во Флориде. После девяти с половиной месяцев космического полета 23 сентября 1999 года, его планировалось вывести на орбиту вокруг Марса. Однако, когда пришло назначенное время, что-то произошло.
Сегодня, ранним утром, около 2:00 утра по летнему тихоокеанскому времени, аппарат включил главный двигатель для выхода на орбиту вокруг планеты. Вся информация, приходившая до этого момента с борта космического корабля, выглядела нормально. Запуск двигателя начался как планировалось, за пять минут до того, как аппарат оказался за планетой (если смотреть с Земли). Управление полетом не зафиксировало сигнала, когда ожидалось, что аппарат должен был выйти из-за планеты35.
Mars Climate Orbiter разрабатывался объединенной командой инженеров и ученых в двух местах - Лаборатории реактивных двигателей (Jet Propulsion Laboratory, JPL), расположенной в Пасадене (Pasadena), штат Калифорния, и на заводе Lockheed Martin Astronautics, LMA в Денвере, штат Колорадо. Завод LMA был ответственен за планирование и разработку Mars Climate Orbiter с точки зрения интеграции и тестирования полетных систем, а также за операцию запуска. Лаборатория JPL несла ответственность за управление проектом, за управление разработкой космического аппарата и приборов, за системотехнику, за планирование миссии, навигацию, разработку операционной системы миссии, разработку наземной системы сбора данных и гарантии безопасности36.
В ходе девяти с половиной месяцев полета наземные службы отслеживали и сравнивали наблюдаемую траекторию аппарата с расчетной. Также наземные службы проверяли все события, происходящие на борту Mars Climate Orbiter. Одним из таких событий было уменьшение углового момента (Angular Momentum Desaturation, AMD). Событие AMD возникало, когда аппарат запускал двигатели малой тяги для устранения углового момента, накопившегося в его маховиках. В основе своей - это калибровочный маневр для поддержания функционирования системных компонентов в заданном диапазоне. Когда возникало событие AMD, происходила следующая последовательность событий:

Аппарат посылал значимые данные на наземную станцию.

Данные обрабатывались программным модулем, называвшимся SM-FORCE.

Результаты работы модуля SM-FORCE помещались в файл, называемый файл AMD.

Данные файла AMD использовались для вычисления изменения скорости аппарата.

Вычисленное значение изменения скорости использовалось для моделирования траектории корабля.
Согласно спецификации модуль SM-FORCE должен формировать данные, помещаемые в файл AMD, используя метрические единицы, то есть ньютон-секунды. Однако по тем или иным причинам модуль SM-FORCE на наземной станции выводил данные, используя английские единицы (фунт-секунды) (в официальном отчете причина не указывалась, и мы не будем строить предположения по этому поводу). Программный модуль, который рассчитывал изменение скорости с использованием данных из файла AMD, ожидал, что они будут в метрических единицах, согласно спецификации. На борту аппарата модуль, который создавал файл AMD, использовал метрические единицы. Это привело к различию между траекториями, вычисленными космическим аппаратом и наземной станцией, а именно параметры траектории, вычисленные наземной станцией, были в 4,45 раза меньше, поскольку 1 фунт-секунда равен 4,45 ньютон-секундам.

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

В программном обеспечении наземной станции было несколько ошибок, и персонал не мог использовать модуль SM-FORCE для расчета траектории корабля. Эти ошибки были исправлены только к четвертому месяцу полета, в районе апреля 1999 года.

Персонал, ответственный за навигацию, не знал о том, что данные об изменении скорости с борта корабля были доступны для сравнения в течение долгого времени после запуска.

Линия обзора между аппаратом и Землей не давала персоналу точно моделировать траекторию корабля, используя наблюдения.
Если бы событие AMD возникало нечасто, коэффициент 4,45 мог и не иметь таких серьезных последствий. Однако из-за формы корабля это событие возникало в 10-14 раз чаще, чем ожидалось. Более того, когда были обнаружены различия в моделях наземной станции, космического корабля и данных наблюдений, неофициальный отчет об этих различиях был отправлен по электронной почте, без использования стандартной процедуры для таких случаев. В конечном итоге эти различия не были устранены до потери космического аппарата.
8 сентября 1999 года персонал наземной станции рассчитал маневр для вывода корабля на орбиту Марса. Это вычисление было сделано с использованием неверной модели. Целью этого маневра была коррекция траектории корабля таким образом, чтобы точка наибольшего приближения к Марсу составляла 226 километров. 23 сентября маневр был выполнен. Запуск двигателя произошел в 09:00:46 по Всемирному координированному времени (UTC), более известному как время по Гринвичу (GMT). Спустя четыре минуты и шесть секунд наземная станция потеряла сигнал с аппарата. Потеря сигнала была вызвана тем, что Orbiter находился за планетой. Но это событие произошло на 49 секунд раньше, чем было предсказано моделью траектории. Поскольку была использована ошибочная модель траектории, корабль оказался в действительности ближе к поверхности планеты, чем ожидалось. Действительная точка максимального сближения оказалась приблизительно 57 километров. По оценке, такая высота оказалась слишком мала для аппарата.

Вывод
«Люди иногда делают ошибки», - заявил доктор Эдвард Уэйлер (Edward Weiler), первый заместитель главы NASA по науке о космосе. «Данная проблема - это не ошибка, это неудача системотехники и систем проверки в наших технологиях, предназначенных для обнаружения ошибки. Вот почему мы потеряли космический аппарат»37.
Одна ошибка была допущена в одной из частей программного обеспечения. Однако целая серия ошибок на протяжении девяти с половиной месяцев полета привела в конечном итоге к потере аппарата. Назвать первоначальную ошибку фундаментальной причиной аварии мешает тот факт, что данный инцидент не был результатом только одной ошибки. Вот три главных составляющих аварии Mars Climate Orbiter:

Если бы было проведено соответствующее тестирование, такая ошибка могла быть быстро обнаружена и исправлена.

Однако, поскольку программное обеспечение наземной станции не было хорошо протестировано, после запуска космического аппарата проявились дополнительные ошибки. Эти ошибки отсрочили наблюдения над проблемой. Вместо девяти месяцев из-за дополнительных ошибок персонал имел только пять месяцев на выяснение причины несоответствий.

Когда несоответствие в итоге было обнаружено, оно так и не было правильно объяснено. Первоначальная причина так и не была выяснена, а это дало бы персоналу информацию о надвигающейся катастрофе.
В отчете комиссии по расследованию первой фазы ее работы также были указаны следующие факторы неудачи и сделаны некоторые дополнительные рекомендации38. Эти факторы и рекомендации главным образом касаются методов и технологий проекта, которые могли быть полезны для программного обеспечения наземных служб.

Обмен информацией. - Обмен информацией является главной проблемой в проекте большого масштаба, программном или любом другом. В случае с Mars Climate Orbiter команды, работавшие над проектами, не связывались действенным образом друг с другом. Команда наземного обслуживания не сообщала о своем беспокойстве по поводу различия траекторий команде управления космическим аппаратом и органам управления проектом. Важная информация от одной команды не передавалась другим командам, что внесло свой вклад в аварию.

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

Проанализируй, что может выйти из строя. - Исследователи считают, что предварительный анализ критических условий системы может помочь предотвратить будущие аварии. Это сходно с анализом отказоустойчивости, анализом процедур восстановления после ошибки и планированием нагрузки, проводимым в распределенных компьютерных средах, обычно встречающихся в системе Интернета.

Самоуверенность. - Комиссия по расследованию обнаружила, что персонал проекта считал посылку космического аппарата на орбиту вокруг Марса легкой задачей, поскольку JPL имела тридцатилетний опыт безошибочной межпланетной навигации. Эта самоуверенность может объяснить недостаток соответствующего тестирования в программных модулях.
Зарисовка #4
Этот инцидент не связан с какой-либо программной ошибкой. В действительности в этой истории программное обеспечение не участвует вовсе. Однако эта история поучительна и забавна и заслуживает места в этой главе. Это укороченная версия истории, в которой описывается субподрядчик, который выполнял работу по прокладке волоконно-оптического кабеля для одной местной телефонной компании. Перед описываемым инцидентом субподрядчик отключил телефонную линию и воспользовался машиной-канавокопателем для прорытия канавы в земле. Однако земля была мокрой от утренней росы, и канавокопатель соскользнул по откосу дороги и столкнул субподрядчика в яму глубиной 10-15 футов. Человек, заметивший этот несчастный случай, подъехал к ближайшему дому, чтобы вызвать по телефону помощь, но телефон не работал. Почему? Потому что телефонная линия была отключена субподрядчиком для проведения работы. Что еще более курьезно, в машине субподрядчика был сотовый телефон, но товарищи раненого по работе совершенно забыли о нем в момент инцидента. В конце концов другой свидетель смог позвонить в службу спасения из другого дома, и инцидент закончился благополучно. Пострадавший был отправлен в больницу без серьезных повреждений. Канавокопатель извлекли из ямы, и общество получило волоконно-оптические кабели39.
Какой урок мы можем извлечь из этого инцидента, который можно было бы применить к наладке программного обеспечения? Главный вывод - всегда имейте резервную копию. Часто в азарте исправления и изменения кода мы чувствуем такую уверенность в своих изменениях, что принимаем их без должного тестирования. Принятые изменения - это такие модификации, которые трудно вернуть в первоначальное состояние, и мы оказываемся в тупике, если возникает проблема. Это напоминает историю с субподрядчиком, который отключил телефонную линию, не подумав о возможности того, что что-то может случиться, и, когда это действительно случилось, он остался без телефона.

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

Авария на телефонной компании AT&T
Для большинства из нас авария на телефонной станции означает то, что мы не можем пользоваться телефонами: не можем звонить сами, и люди не могут звонить нам. Аварии - это ожидаемый и принимаемый риск в этой индустрии. Ураганы могут повредить телефонные линии, подземные кабели могут быть повреждены из-за человеческой ошибки или землетрясения или же возможны ошибки в программном обеспечении, которое управляет сетью.
К 15 января 1990 года в компании AT&T произошла авария, охватившая всю страну и продолжавшаяся девять часов. Причина состояла в ошибке в программном обеспечении, которое должно было сделать эту систему более эффективной. Восемь лет спустя, 13 апреля 1998 года, на AT&T произошла другая крупная авария в сети ретрансляции кадров (frame relay network), которая затронула банкоматы, операции с кредитными картами и другие службы, связанные с передачей бизнес-данных. Авария длилась 26 часов. И опять ошибка была внесена при обновлении программного обеспечения.

Сделала ли AT&T одну и ту же ошибку дважды или здесь было что-то еще?

История: авария 1990 года
В 1990 году телефонная сеть AT&T состояла из 114 соединенных между собой систем коммутирования вызовов 4ESS (4ESS toll switching systems) (это представление является упрощением). Для нашего обсуждения мы мысленно смоделируем сеть AT&T в виде схемы. В этой схеме существует 114 узлов (точек пересечения) и каждый узел представляет один из 114 коммутаторов 4ESS. Линии, нарисованные между узлами, изображают коммуникационные каналы между ними.
В такой телефонной сети, когда один из узлов сталкивается с проблемой, он посылает сообщение «не беспокоить» всем узлам, с которыми он соединен. Это сообщение информирует соседний узел о том, что данный узел не может обрабатывать новые вызовы и просит соседний узел считать его не работающим. Тем временем аварийный узел активирует процесс восстановления после сбоя, который длится от четырех до шести секунд. По окончании процесса восстановления аварийный узел посылает сообщение, известное как Начальное адресное сообщение (Initial Address Message, IAM), всем соседним узлам, сообщая им о своем новом статусе и требуя направлять вызовы на восстановленный узел.

В середине декабря 1989 года AT&T произвела обновление программного обеспечения на коммутаторах 4ESS с целью увеличения производительности системы и введения быстрого процесса восстановления после ошибки. Приблизительно в 2:30 по Восточному стандартному времени (EST) 15 января 1990 года на 4ESS коммутаторе в Нью-Йорке возникла небольшая аппаратная проблема, и коммутатор начал процесс восстановления, как было описано выше. После того как Нью-Йоркский коммутатор исправил проблему, он послал сообщение IAM для уведомления соседних коммутаторов, что он готов продолжать работу. Однако обновление программ, проведенное в середине декабря, внесло в действия ошибку. Эта ошибка проявилась, когда коммутатор получил два IAM сообщения с интервалом 1/100 секунды. Некоторые данные в коммутаторе оказались искажены, и он прекратил обслуживание, перейдя к инициализации. Когда соседние узлы выходили из строя, они запускали тот же самый процесс восстановления. Поскольку все коммутаторы были одинаковы, та же последовательность событий каскадом распространялась от одного коммутатора к другому и вывела из строя всю систему.

В течение дня инженеры AT&T смогли стабилизировать сеть, уменьшив нагрузку на нее. К 23:30 EST они смогли очистить все звенья сети, и система практически вернулась к нормальному состоянию.

Во вторник, 16 января 1990 года, инженеры AT&T смогли идентифицировать и выделить ошибку, которая была отслежена до набора ошибочных кодов. Этот код активировался в ходе процедуры восстановления коммутатора. Отрывок кода, который вызвал аварию, представлен ниже41:

1.do {
2. ...
3. switch (expression){
4. case (value 0):{
5. if (logical_test){
6. ...
7. break;
8. }else {
9. ...
10. }
11. ...
12. break;
13.}
14. ...
15. }
16. ...
17. }while (expression);
В данном случае виновным оказался оператор break в строке 7. Согласно реализации, если logical_test прошел успешно, программа переходит к строке 6 для выполнения расположенных там операторов. Когда выполнение программы доходит до строки 7, оператор break заставляет программу покинуть блок оператора switch, расположенного между 3 и 15 строками, и исполнять код начиная со строки 16. Однако эта часть исполнения не входила в намерения программиста. Программист желал, чтобы оператор break в седьмой строке прерывал выполнение условного оператора if-then и чтобы после исполнения седьмой строки исполнение продолжилось со строки 11. В таблице 2.1 показаны различия в исполнении программы, как это было задумано и как это было реализовано.
Таблица 2.1. Желаемые и реализованные последовательности инструкций, которые привели к аварии в телефонной сети AT&T 1990 года

ход выполнения реализация ожидалось
шаг 1 строка 2 строка 2
шаг 2 строка 3 строка 3
шаг 3 строка 4 строка 4
шаг 4 строка 5 строка 5
шаг 5 строка 6 строка 6
шаг 6 строка 7 строка 7
шаг 7 строка 16 строка 11 (не верно)
шаг 8 строка 17 строка 12 (не верно)
шаг 9 - строка 16 (не верно)

Вывод: авария 1990 года
Программная ошибка, приведшая к аварии 1990 года, - это типичная ошибка новичка. Но ошибки делаем все мы, и даже ветеран с 20-летним стажем может совершить случайно глупую ошибку. Если ошибки неизбежны, вопрос состоит в том, что мы можем сделать для того, чтобы отыскать ошибку до того, как она станет достоянием общества? У нас нет никакого знания из первых рук о внутренней кухне разработки программ в AT&T в 1990 году. Следовательно, мы не можем оценить вклад других причин. В официальном отчете AT&T говорилось:
Мы считаем, что процессы планирования, разработки и тестирования программ, которые мы используем, базируются на прочных и качественных основах. Все будущие программы будут также скрупулезно тестироваться. Мы используем опыт, приобретенный при решении этой проблемы, для дальнейшего улучшения наших методов42.
Мы не считаем возможным обвинять в аварии 1990 года процесс разработки программного обеспечения в AT&T и не имеем оснований считать, что AT&T не протестировала тщательно обновление для своих программ. Оглядываясь назад, легко говорить, что, если бы разработчики только протестировали свои программы, они сразу увидели бы эту ошибку. Или то, что, если бы они проверили код, они, возможно, обнаружили бы дефект. Проверка кода может быть и помогла бы в данном случае. Однако единственный случай, когда проверка кода помогла бы найти данную ошибку, если бы другой специалист увидел именно эту строку кода и спросил первого программиста, входил ли этот код в его (ее) намерения. А единственная причина, по которой этот специалист мог бы задать такой вопрос, - знакомство со спецификацией к этому конкретному блоку кода.

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

Эта ошибка требовала, чтобы нагрузка на сеть была продолжительной. Когда нагрузка на сеть уменьшалась, действие дефекта, по существу, исчезало43.

Эта ошибка зависела от временных параметров. Чтобы ошибка активировалась, было необходимо, чтобы были получены два IAM сообщения от одного и того же коммутатора с интервалом менее 10 миллисекунд.

Тот факт, что на всех коммутаторах было установлено одинаковое программное обеспечение, делал систему расширяемой. Однако был риск в том, что, если на всех коммутаторах был один и тот же дефект, они все оказывались чувствительными к одной и той же ошибке.
История: авария 1998 года
13 апреля 1998 года в 2:30 после полудня к коммутатору системы ретрансляции кадров Cisco Stratacom BPX был направлен техник для обновления транк-карты (trunk-card)44. Коммутатор Stratacom BPX содержал две транк-карты, одна из которых была активной, тогда как другая находилась в ждущем режиме и выполняла функцию резерва. Фирма AT&T использовала две процедуры обновления транк-карт. Одна процедура использовалась, если коммутатор был в текущее время подключен к сети и активен, тогда как другая процедура применялась, если коммутатор был изолирован, то есть не соединен с сетью.
Согласно первому сценарию, то есть когда коммутатор считался активным, процедура требовала, чтобы техник заменил сначала карту, находящуюся в ждущем режиме. Как только становилось ясно, что состояние новой карты стабильно, старая активная карта переводилась в ждущий режим, а новая карта становилась активной. Проведя эту операцию, техник мог заменить оставшуюся карту (теперь находящуюся в ждущем режиме). При второй процедуре предполагалось, что коммутатор отключен от сети и техник мог менять обе карты одновременно.

Когда техник прибыл на место, он посчитал, что коммутатор, которому требуется обновление, не подключен к сети, поскольку казалось, что через него не проходил никакой сетевой трафик. Однако коммутатор был подключен к сети и активен. К несчастью для техника и для AT&T, обе карты имели дефекты. Как только карты были установлены и активированы, они немедленно выслали коммутатору поток сообщений об ошибках. Эти сообщения от транк-карт активировали ошибку в программном модуле коммутатора. Этот дефект вызвал распространение передачи сообщений об ошибках к другим коммутаторам сети, ко всем 145. Объем этих посланий был достаточно велик, для того чтобы быстро перегрузить все коммутаторы, что очень действенно вывело из строя всю систему приблизительно к 3:00 пополудни45.

Информации об ошибках в программном обеспечении транк-карт и коммутатора Cisco немного. Элка Ярвис (Alka Jarvis), менеджер по программному обеспечению Cisco Systems, 28 мая 1998 года на заседании сессии Международной недели качества программного обеспечения (International Software Quality Week) прокомментировал, что код, который вызвал аварию в сети AT&T, являлся наследством прошлого46.

Компания AT&T смогла быстро изолировать аварийный коммутатор, к 23:00 он был отключен от сети. Оставшаяся задача состояла в том, чтобы просто перестроить всю сеть, одну часть за другой. К 2:00 пополудни 14 апреля 1998 года 99,9 % сети ретрансляции кадров были снова работоспособны. Однако определение причины аварии заняло у AT&T около недели, и 22 апреля 1998 года фирма выпустила отчет, очерчивающий причину выхода сети из строя.

0

14

Вывод: авария 1998 года
Хотя в аварии 1998 года и участвовало программное обеспечение, существует множество причин, внесших свой вклад в данное происшествие. Эта авария отличалась от аварии 1990 года тем, что процедурная ошибка в ходе обновления запустила скрытые программные дефекты. Однако сходств очень много.

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

Ошибочный код не был проверен должным образом. При аварии 1990 года это был новый код от AT&T. При аварии 1998 года - старый код от Cisco Systems.

Программные дефекты в обоих случаях представляли собой проблемы со скрытыми граничными условиями, которые было трудно протестировать и которые, по всей вероятности, так и не были протестированы.
Авария 1998 года в сети AT&T выявила многочисленные просчеты в процедурах и процессах обслуживания сети и продемонстрировала трудности в разработке и поддержании в рабочем состоянии надежной сети. Очевидно, AT&T извлекла урок из своих ошибок и исправила многочисленные процедурные и функциональные недостатки и ввела многочисленные планы для восстановления после аварий, чтобы минимизировать риск другой общесистемной аварии47.
Переполнение буфера
18 июля 2000 года через список рассылки BugTraq было опубликовано детальное описание уязвимости систем безопасности Microsoft Outlook и Outlook Express. BugTruq - это список рассылки (mailing list), посвященный обсуждению компьютерной безопасности. Указанная уязвимость, по существу, обеспечивается ошибкой, обычно называемой в программной индустрии переполнение буфера (buffer overflow). В наиболее простой форме переполнение буфера случается, когда программа старается поместить данные в область памяти, которая слишком мала для их хранения. Следующий отрывок кода представляет собой пример на языке С:
1. char Array[10];
2. strcpy (Array, "Это вызовет переполнение буфера");

Размер массива составляет 10 символов, а сообщение: «Это вызовет переполнение буфера» состоит из 31 символа. Функция strcpy() пытается скопировать 31 символ в область, размеры которой позволяют хранить только 10 символов, и, таким образом, часть сообщения пишется за пределами разрешенной области. Когда такое случается, программа иногда претерпевает сбой. В другой раз программа может продолжать работу в течение некоторого времени без побочных эффектов. Но если сообщение составлено подходящим образом, это может привести к выполнению встроенного в сообщение «вируса», что вызовет заражение компьютера этим вирусом.

До настоящего момента наибольшую заботу о безопасности компьютера вызывали многообразные вирусы, которые требовали от пользователей предпринять некоторые действия для осуществления заражения. К таким вирусам относятся такие, как «ILOVEYOU» в 1999 году и «Melissa» в 1998 году. В обоих случаях для активации вируса пользователя хитростью заставляли запустить программу или открыть файл. Однако ошибка переполнения буфера в Outlook не требует вмешательства конечного пользователя. Для того чтобы вы подверглись атаке, достаточно просто получить электронное письмо, и это делает атаку особенно трудной для отражения.

В отличие от прочих случаев, описанных в этой главе, эта ошибка не ограничивается программой Microsoft Outlook. Как ошибка, переполнение буфера существует последние 10 лет, и это хорошо известное уязвимое место систем безопасности. Вне пределов проблем безопасности сетей переполнение буфера также очень распространенная ошибка - вероятно, каждый создавал такой дефект в какой-то момент своей карьеры. Когда бы вы использовали переменную фиксированного размера, такую, как массив, вы рискуете создать ошибку переполнения буфера. Поскольку эта проблема так распространена, вместо того чтобы детально описывать ошибку в Microsoft Outlook, мы поговорим об ошибке переполнения буфера вообще - как эта ошибка создается, какого рода риск для безопасности она может представлять и что мы можем сделать, чтобы избежать ее.

История
Причину переполнения буфера понять легко. Оно происходит, когда мы пытаемся записать слишком много данных в фиксированную область памяти (буфер). Чтобы понять, как переполнение буфера может вызвать сбой программы или стать уязвимым местом в системе безопасности, мы должны проникнуть во внутреннюю логику работы компьютера.
Когда вы пишете программу на языке высокого уровня, таком, как С, компилятор переводит программу в машинный код. Машинный код, по существу, представляет собой последовательность инструкций низкого уровня и данных. Например, рассмотрим следующую основную программу:

1.main(){
2.printf("Hello World");
3.}

Знаменитая программа «Здравствуй, мир» создает 300 294 байта исполняемого кода при использовании компилятора 'С' GNU (GCC) в Windows NT, и это выглядит примерно так:

0x401000 55 89 e5 83 ec 10 83 3d 00 20 40 00 00 74 01 cc
0x401010 d9 7d fe 66 8b 45 fe 25 c0 f0 ff ff 66 89 45 fe

0x401040 48 65 6c 6c 6f 20 57 6f 72 6c 64 00 55 89 55 89
0x401050 e5 e8 94 01 00 00 68 40 10 40 00 e8 92 01 00 00
0x401060 83 c4 …

Что-то довольно непонятное, не так ли? Эти числа - это то, что компьютер использует, когда исполняет написанную вами программу. Числа в этом коде представлены в шестнадцатеричном виде. Первая колонка представляет собой адрес памяти, где находится программа, а оставшиеся колонки показывают содержимое этих адресов памяти. Каждая колонка увеличивает значение адреса на единицу. Таким образом, по адресу 401000 хранится значение 55, по адресу 401001 хранится значение 89 и так далее. Некоторые из этих чисел - команды, которые говорят компьютеру, что делать, другие представляют собой данные, используемые компьютером. В данном случае компьютер берет первое значение, 55, и интерпретирует его как команду выполнить некоторое действие. Затем он переходит к следующему значению - 89. Компьютер знает, что команда 89 требует параметр, который хранится в следующем адресе и имеет значение е5. Таким образом, компьютер выполняет команду 89 е5 и затем переходит к значению, идущему следом за е5. Так компьютер исполняет эти команды по одной за раз. В программе «Здравствуй, мир» строка «Hello, world» представляет собой данные. Если вы можете прочитать шестнадцатеричные значения и знаете коды ASCII, вы можете увидеть, что строка «Hello, world» расположена по адресу 0х401040.

0x401040
48(H)65(e)6c(l)6c(l)6f(o)20()57(W)6f(o)72(r)6c(l)64(d)00

Этот набор чисел выглядит совершенно неотличимым от другого набора чисел. Что же не дает компьютеру рассматривать эти числа, как последовательность команд? Ничего, кроме логики, реализованной в программе и которая является главной проблемой при ошибке переполнения буфера. Если вы совершаете ошибку, компьютер считает эти данные командами и исполняет их как таковые. У него нет способа узнать, что эти значения относятся к данным. Такие команды бессмысленны, и программа, наиболее вероятно, остановится. Таким образом, задача потенциального нарушителя - использовать эту ошибку, чтобы заставить компьютер исполнять те данные, которые он ему предоставит. Следовательно, нарушители, которые хотят атаковать ваш компьютер с помощью ваших программ, должны сделать две вещи:

Вставить свой код в память.
Заставить компьютер исполнять этот код.
Ошибка переполнения буфера дает хакеру возможность сделать и то и другое. Поскольку программа не проверяет размер буфера, когда пишет в него, нарушитель может поместить произвольное содержимое в область памяти, идущую за буфером, - и сражение наполовину выиграно. Вторая половина будет выиграна, когда потенциальный хакер определит, как можно заставить компьютер выполнить код, который он вставил в вашу программу48.

Вывод
Из всех случаев, изученных в данной главе, переполнение буфера, вероятно, самый простой для понимания и объяснения. Он все время рядом, но тем не менее он все еще так распространен. Научимся ли мы чему-нибудь, как индустрия? Почему мы продолжаем делать эти ошибки?

Не помогают языки программирования. Ошибки переполнения буфера приобрели характер эпидемии в тех языках, в которых нет встроенных средств проверки границ, таких, как С и С++. Эти языки дают программистам возможность манипулировать компьютером произвольно. Эта сила доверяется программистам, и от них ждут, что они будут программировать корректно и безопасно. Ожидается также, что они будут проводить явные проверки границ, если это необходимо. С другой стороны, такие языки, как Java, проводят явные проверки границ, и вероятность того, что ошибка переполнения буфера может быть использована, очень низка. Однако язык Java ограничивает возможности программиста. Он отнимает у него возможность напрямую манипулировать пространством памяти машины. Нельзя сказать, что переполнение буфера невозможно в программе на Java. Это просто означает, что программист должен внести серьезные искажения, чтобы вызвать переполнение буфера на Java. Когда это случается, определить причину крайне тяжело. И поскольку большая часть виртуальной машины Java написана на С и С++, всегда существует опасность ошибки переполнения буфера в виртуальной машине Java.

Программистам нельзя доверять. Программисты - люди, а люди делают ошибки. Я по невнимательности много раз за свою жизнь создавал ошибки переполнения буфера. Много раз ошибки возникали, поскольку я создавал макет программного модуля и проверка границ массивов - это последнее, о чем я думал. Но макет имеет обыкновение находить способ проникать в продукт. В другой раз ошибки возникали, потому что я делал допущения по поводу кода и процесса функционирования и считал, что переполнение буфера невозможно. Как это обычно бывает, как только я делаю какие-либо допущения, что-нибудь показывает мне мою неправоту. Часто ошибки появляются из-за моей лени. Написание кода проверки на переполнение буфера - задача в большинстве случаев легкая, но обработка условий обнаружения нарушений границ может оказаться трудным и надоедливым делом. Могу ли я просто прервать выполнение программы? Или я должен сообщить об ошибке вызываемой функции? Как эта функция будет обрабатывать эту ошибку? Прерываю ли я выполнение программы в вызываемой функции до бесконечности? Проще всего не иметь с этим дела и допустить, что такого не случится. Я займусь этим, если те, кто тестируют программы, докажут, что я не прав.

Языковые конструкции делают это сложным. Проведение проверки границ в некоторых языках может оказаться трудным делом - на ум приходит использование функции sprintf(). Поскольку sprintf() принимает переменное число аргументов, при использовании этих аргументов от программиста требуется посчитать размеры буфера. Это может легко вызвать переполнение, поскольку вы не понимаете нюансов языка. В С и С++ строка «Hello World» требует 12 символов памяти, потому что язык определяет, что строка должна оканчиваться символом с кодом «0». Иными словами, код «0» добавляется в строке после символа «d». Если вы выделили буфер размером в 11 символов, считая, что он вместит в себя всю строку, то использование любых строковых функций, таких, как strcpy(), приведет к ошибке переполнения буфера, и это ударит по вам, когда вы меньше всего ожидаете.
Легко говорить о способах окончательного избавления от ошибок переполнения буфера. Например, прекратите использовать небезопасные языки, такие, как С и С++, и приучите себя писать программы с позиций «оборонительного программирования»49. Мы понимаем, что это легче сказать, чем сделать. Если мы примем то, что ошибка переполнения буфера неизбежна, и то, что нам необходимо использовать небезопасные языки программирования, тогда единственным решением будет поиск ошибки. Чем раньше мы обнаружим ошибку, тем меньше шанс, что она огорчит нас в будущем.

С точки зрения безопасности ошибка не беспокоит нас, если программа зависает, но беспокоит, если ее можно использовать. Теперь сделаем ударение на том как предотвратить ошибку переполнения буфера от использования злоумышленником. Есть многочисленные исследовательские проекты и коммерческие продукты, касающиеся этой темы, и мы считаем, что читателям нужно ознакомиться с этими документами для получения дальнейшей информации50.

Заключение
Ошибки, обсуждаемые в этой главе, за несколькими исключениями, существовали или существуют в настоящее время. Сейчас тысячи разработчиков программ устраняют ошибки, работая сверхурочно. Некоторые из этих ошибок забавны, тогда как другие - подлые или трагичные. Тем не менее это совсем не забавно, если вы - один из тех, кто работает по выходным, устраняя ошибки. Однако цена, которую платят разработчики программ, мизерна по сравнению с последствиями этих ошибок. В этой главе мы узнали, что цена ошибки может быть астрономической. Миллионы долларов, затраченные на оборудование и работу, исчезают без следа. Человеческая боль и страдания, даже смерть могут быть вызваны простой ошибкой в программе.
Мы узнали, что, несмотря на все тестирование, технологии и процедуры, ошибки неизбежны. И сбои, проявляющиеся в конечном продукте, как правило, являются результатом целой серии ошибок. Обычно не существует какой-то одной причины. Вместо этого есть целая коллекция причин, предотвращающих обнаружение и удаление ошибки до рокового финала. Например, простая ошибка программирования привела к аварии на AT&T в 1990 году. Однако, если бы был проведен тест по исполнению кода в ошибочной его части, дефект был бы выявлен раньше, и это спасло бы AT&T от аварии телефонной сети общенациональных масштабов. Является ли главной причиной ошибки программист, написавший неверный код, или отдел тестирования, который позволил дефекту проникнуть в код конечного продукта?

Мы узнали, что способность находить ошибки также важна, как способность предотвращать их. Чем раньше мы сможем найти ошибку, тем дешевле нам встанет ее исправить. Мы узнали, что программное обеспечение может функционировать в точности так, как указывает спецификация, и все же мы будем считать его дефектным, хотя оно работает именно так, как ему указали. Мы узнали, что мы должны понимать подсказки, которые дает нам система, и должны всегда задаваться вопросами, оценивать и понимать причины, стоящие за этими подсказками. Но что наиболее важно, мы узнали, что перед лицом проблем нам следует быть скромными. Неспособность признать, что ошибки возможны и вера без сомнений в наши создания может сделать нас слепыми перед лицом потенциальных аварий программ. Вот объяснение того, что гордость - один их смертных грехов.

Мы определили много причин тех ошибок, о которых рассказано в этой главе. Эти причины кратко перечислены и обобщены ниже.

Недостаток понимания инструментов и конструкций языка:
Случаи - авария 1990 года на AT&T, ошибка переполнения буфера.
Описание - дефект возникает, когда программист неправильно понимает конструкции языка. При аварии на AT&T 1990 года ошибка заключалась в неверном расположении оператора break. Типичная ошибка переполнения буфера может быть вызвана непониманием средств манипуляции со строками в стандартных функциях С и С++.

Повторное использование модулей без понимания:
Случай - Ariane-5.
Описание - унаследованный программный модуль был использован повторно, но наблюдался недостаток понимания требований этого модуля. Не было сделано попыток оценить правомерность использования.

Изменения и обновления программ:
Случаи - аварии на AT&T 1990 и 1998 годов.
Описание - ошибка проявилась в ходе и после окончания обновления программ, которое было направлено на повышение производительности системы.

Игнорирование неожиданных результатов:
Случаи - Mars Climate Orbiter, Therac-25.
Описание - в обоих случаях была масса предупреждений и подсказок из различных источников о том, что что-то не так. Предупреждения проявлялись как неожиданные результаты и поведение. Но эти предупреждения регулярно игнорировались, и должное расследование не было проведено. В случае Mars Climate Orbiter проблема состояла в несовпадении между рассчитанными моделями с борта космического корабля и с наземной станции. В случае с Therac-25 проблема была в постоянных неполадках и Therac-20, и Therac-25.

Непонимание подсказок:
Случаи - Mars Climate Orbiter, Therac-25, Компания Х, Компания Y.
Описание - ключи, указывающие на потенциальные ошибки, не интерпретировались корректно, что в конечном счете привело ко всем описанным авариям. И в случае с Компанией Х, и в случае с Компанией Y подсказки прекрасно описывали причину симптомов, но эти подсказки первоначально не были приняты во внимание.

Недостаток подходящих средств мониторинга:
Случаи - Mars Climate Orbiter, Therac-25, Компания Х, Компания Y.
Описание - хорошие средства мониторинга могут помочь обслуживающему персоналу обнаружить и решить проблему до того, как она приобретет серьезные последствия. Может быть, несправедливо относить в эту категорию Mars Climate Orbiter, поскольку ученые были ограничены технологиями и законами физики в том, что они могли наблюдать. Тот факт, что они не могли наблюдать действительную траекторию космического аппарата, ограничивал их возможности в определении правильности их модели. В случае Therac-25 сообщения об ошибках не имели достаточно описательного характера, чтобы встревожить операторов потенциальными проблемами в машине. Так же наблюдался явный недостаток обратной связи, позволяющей оператору точно знать, что делает машина. Проблемы в Компаниях Х и Y могли бы быть минимизированы, если бы обслуживающий персонал смог определить падение производительности базы данных до аварии.

Неверная или бедная спецификация:
Случай - Ariane 5.
Описание - спецификация обработки ошибки определяла, чтобы ошибочное значение было помещено в память, используемую навигационным компьютером. Реализация программного обеспечения точно соответствовала спецификации. Навигационный компьютер использовал это значение для осуществления маневра с использованием двигателей, что вызвало катастрофу. В данном случае спецификация обработки ошибки была ошибочна и вызвала крушение.

Отклонение от спецификации:
Случай - Mars Climate Orbiter.
Описание - спецификация для Mars Climate Orbiter была очень ясной: единицы измерения должны быть метрическими, а не английскими.

Унаследованные ошибки:
Случаи - Therac-25, авария на AT&T 1998 года.
Описание - унаследованные программные модули содержали ошибки, которые не были обнаружены в их предыдущем воплощении.

Отклонение от должной процедуры:
Случаи - авария на AT&T 1998 года, компания Х.
Описание - процедуры были разработаны для того, чтобы помешать нам сделать ошибку, а когда процедуре не следуют, а идут коротким путем, возникают нежелательные эффекты.

Небезопасные средства:
Случай - переполнение буфера.
Описание - одной из главных причин ошибки переполнения буфера является «небезопасность» таких программных языков, как С и С++, в которых программа зависит от того, провел ли программист явную проверку границ массивов для предотвращения этих ошибок.

Человеческий фактор:
Случай - переполнение буфера.
Описание - мы все знаем, как предотвращать ошибки, и все же мы продолжаем их делать.

Эго и самоуверенность:
Случаи - Therac-25, Mars Climate Orbiter.
Описание - эго может встать на пути объективной оценки систем. Самоуверенность может заставить нас не подвергать сомнению наши допущения. Результатом такого отношения станет то, что мы не будем обращать внимания на имеющиеся ключи, которые указывают на потенциальные дефекты программ.

Неполное тестирование:
Случаи: Ariane 5, Mars Climate Orbiter, Pentium, авария на AT&T 1990 года.
Описание - легко рассуждать, глядя в прошлое, но большая часть этих ошибок могла бы быть обнаружена при «правильном» тестировании. В случае Ariane 5 неполнота требований и недостаток возможностей по имитации функциональной среды привели к тому, что инженеры вынуждены были отказаться от теста, который обнаружил бы ошибку. Неясно, проводилось ли тестирование в случае с Mars Climate Orbiter, поскольку персонал в ходе космического полета все еще занимался устранением ошибок. В случаях ошибки в процессоре Pentium и аварии на AT&T 1990 года проведенные тесты не принимали во внимание особенности алгоритма, поэтому некоторая часть кода не была протестирована. В случае с ошибкой в Pentium тестирование на основе случайной выборки не было достаточным для оценки всех значений в справочной таблице. При аварии на AT&T 1990 года тест не охватывал сценарий восстановления коммутатора.
Задача
Вы тестировали набор Web-страниц на Web-сайте вашей компании. Вы нажали на ссылку на Web-страницу А, и все прошло великолепно. Вы продолжили тестирование других Web-страниц на сайте и случайно вернулись на Web-страницу А опять. Но в этот раз ее содержимое оказалось устаревшим. Вы недоуменно посмотрели на страницу и перезагрузили ее. Теперь она снова выглядела нормально. Не доверяя тому, что вы видите, вы опять перезагрузили страницу, и страница снова оказалась правильной. Полагая, что три - это число магическое, вы подумали про себя, что если страница и теперь окажется правильной, значит, то, что вы видели, - это просто случайность. Вы перезагрузили страницу еще раз, и оказалось, что ее содержимое снова является устаревшим. Вы боднули головой монитор. После 10 минут, проведенных в перезагрузке этой страницы снова и снова, вы определили, что она загружается правильно 34 раза и неправильно 12 раз. Что может быть причиной ошибки?
Вот некоторые подсказки, которые помогут вам поразмышлять о причине ошибки. Архитектурно есть пять Web-серверов, обрабатывающих запросы браузера. Каждый Web-сервер может связываться с одним из четырех серверов приложений. Сервер приложений извлекает данные из базы данных и реализует бизнес-правила. Для ускорения работы каждый сервер хранит данные в локальном кэше.

0

15

Да ладно заливать, Intel делает самые стабильные и безглючные процы :jumping:

0

16

SuperPuper, докажи.

0

17

OPTERON
Зачот!  :D Сохраню себе как FAQ по убиванию штеудеев.

0

18

SuperPuper написал(а):

Да ладно заливать, Intel делает самые стабильные и безглючные процы

Это вовсе не важно.Совершенно пофигу чего там делает Ынтел. :rofl:

0