Saturday, December 27, 2008

Легенда о восстановлении Unix

Сейчас много мыслей о том, что ждёт нас в будущем, в 2009 году, да и после. Но почему бы на мгновение не вернутсья в прошлое и не восхититься тем, как хардкорные юниксоиды того времени выкручивались, восстанавливая систему?

Это — перевод статьи Mario Wolczko, опубликованной в Usenet в 1986.

Бывало ли когда-нибудь, что ты оставлял терминал залогиненным, просто чтобы вернуться и увидеть, как (предполагаемый) друг написал в нём rm -rf ~/* и стоит возле клавиатуры: — Одолжи мне пятёрку до четверга, или я нажимаю «энтер».

Без всякого сомнения, этот человек не понимает, какую травму он может нанести, и воспринимает всё как милую шутку.

Это была тихая среда. Если быть точным — среда 1-го октября, 15:15 по британскому летнему времени. Питэр, мой коллега, отошёл от своего терминала и сказал мне: — Марио, у меня тут небольшая проблема с отправкой почты.

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

В терминале было странное сообщение об ошибке, примерно такое (я уже не помню всех деталей): cannot access /foo/bar for userid 147

Сначала я подумал: у кого userid 147? Отправитель сообщения, получатель или ещё что-то? Тогда я перешёл к другому, уже залогиненному терминалу, и набрал

grep 147 /etc/passwd

просто, чтобы получить ответ

/etc/passwd: No such file or directory. 

Тут же я предположил, что чего-то нет. Всё подтвердилось, в ответ на

ls /etc

Я получил

ls: not found. 

Я посоветовал Питэру, что хорошей идеей будет ничего сейчас не трогать, и пошёл искать нашего системного администратора.

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

# cd
# rm -rf *

Вот дерьмо, подумал я. И это ведь всё объясняет.

Я даже не помню, что происходило в следующие минуты; моя память словно размыта. Я помню только, что мы пробовали ls (снова), ps, who и, может, ещё несколько команд — всё бесполезно. Следующее, что я помню: я снова у моего терминала (многооконный графический терминал), набираю

cd /
echo *

Я должен выразить благодарность Дэвиду Корну, ведь он сделал echo встроенной внутрь командной оболочки; не нужно и говорить, что бинарный файл /bin/echo за компанию со всем /bin был удалён. Что прояснилось в следующие несколько минут, так это то, что /dev, /etc и
/lib неразлучимо исчезли, но, к счастью, Нэйл прервал rm в тот момент, когда она была где-то между /news и /tmp; /usr и
/users остались нетронуты.

Тем временем Джэймс добрался до нашего шкафа с кассетами и вытащил что-то с надписью о том, что это бэкап корневой файловой системы, сделанный четыре недели назад. В воздухе витал вопрос: — Как же нам восстановить содержание кассеты?

Мы ведь потеряли не только /etc/restore — все файлы устройств контроллера ленточных накопителей были стёрты. А где живёт mknod? Правильно, /etc. Как насчёт восстановить любой из них по Ethernet с другого VAX? Понятное дело, /bin/tar пропал, а rcp люди из Беркли заботливо положили в
/bin в дистрибутиве 4.3. Кроме того, для работы сети нам нужен как минимум /etc/hosts. Версию cpio мы нашли в /usr/local, но без контроллера ленточных накопителей это, к сожалению, бесполезно.

В качестве альтернативы мы могли бы вытащить загрузочную ленту и пересобрать корневую файловую систему, но ни Джэймс, ни Нэйл никогда не делали этого прежде, и мы не были уверены, что это и есть то, что нам нужно — полностью переформатированный диск и потеря всех наших пользовательских файлов (мы делаем бэкапы пользовательских файлов каждый четверг; по закону Мёрфи всё и должно было случиться именно в среду).
Ещё решение — позаимствовать диск от другого VAX, загрузиться с него, и уже потом разбираться; но тогда бы пришлось звать DEC-инженера — это в самом лучшем случае. У нас было много пользователей, в муках завершающих свои кандидатские диссертации, и потеря возможно недельной работы была немыслима.

Так что же делать? Следующей идеей было написать программу, которая бы создала дескриптор устройства для контроллера ленточных накопителей, но все мы знаем, где живут cc, as и ld. Или, может, сделать минимального вида /etc/passwd, /etc/hosts и прочее, чтобы /usr/bin/ftp смог работать. По счастливой случайности, у меня оказался всё ещё открытый в одном из моих окон gnuemacs — мы могли бы воспользоваться им, чтобы создать passwd и всё остальное, но первым шагом нужно создать директорию, чтобы поместить их туда. Разумеется, был удалён /bin/mkdir, то же самое произошло с /bin/mv, так что мы не могли переименовать /tmp в /etc. Однако это явно была правильная линия для атаки.

К тому моменту к нам присоединился Alasdair, наш местный UNIX-гуру, как оказалось, знающий ассемблер VAX. Так что наш план стал таким:
  1. написать на ассемблере программу, которая бы могла либо переименовать /tmp в /etc, либо создать /etc;
  2. заассемблировать её на другом VAX, сделать uuencode;
  3. записать её в в uu-закодированный файл, используя мой GNU, и сделать uudecode (какой-то умный человек догадался поместить uudecode в /usr/bin).
Остаётся запустить программу. Ещё одно чудо: терминал, который использовался для нанесения ущерба, всё ещё был суперпользовательским после su (достаточно вспомнить, что su находится в /bin), так что у нас хотя бы появился шанс, что всё это заработает.

И вот, мы уже стоим на очаровательном пути к успеху. Потратив всего час, мы состряпали примерно дюжину строчек на ассемблере для создания /etc. Обрезанный бинарный файл оказался длиной всего 76 байт, так что мы сконвертировали его в HEX (читается немного лучше, чем вывод uuencode), и записали, используя мой редактор. Если у вас вдруг когда-нибудь возникнет такая проблема, вот HEX на будущее:

070100002c000000000000000000000000

0000000000000000000000000000000000

dd8fff010000dd8f27000000fb02ef0700

0000fb01ef070000000000bc8f88000400

00bc012f65746300

У меня была подручная программа (а что, у кого-то не было?) для конвертирования ASCII HEX в двоичный код, и вывод /usr/bin/sum совпадал с нашим оригинальным бинарным файлом. Но стоп, секундочку — как же ты установишь права на выполнение без /bin/chmod? За несколько секунд сформированная мысль (которая, как обычно, завершает пару минут раздумий) принесла решение проблемы: нужно записать бинарный файл поверх уже существующего файла, для которого я являюсь владельцем. Вот и хорошо.

Мы вернулись к терминалу с правами суперпользователями, с осторожностью вспомнили поставить umask на 0 (чтобы я мог создавать внутри файлы, используя свой GNU), и запустили бинарный файл. Теперь у нас был /etc, с доступом на запись для всех. Теперь оставалось всего несколько шагов: нужно было создать passwd, hosts, services, protocols, (etc), после чего ftp был готов к работе. Потом мы восстановили содержимое /bin по сети (это невероятно, как тебе начинает жутко не хватать ls после всего нескольких коротких часов без него) и взяли файлы из /etc. Ключевым файлом был /etc/rrestore, с его помощью мы восстановили /dev с бэкап-кассеты. Тут и сказочке конец.

А вот теперь мы задаём себе вопрос, в чём же мораль этой истории. Ну, для начала, стоит хорошо запомнить вечные слова: не паниковать. Мы ведь сначала и хотели просто перезагрузить компьютер и попробовать всё как single-пользователь, но, к сожалению, система при загрузке не нашла бы /etc/init и /bin/sh. Здравое мышление спасло нас от таких действий.

Следующая вещь, которую стоит запомнить, это то, что утилиты UNIX могут использоваться с действительно нетипичными для них целями. Даже без моего gnuemacs мы бы могли выжить, используя, скажем, /usr/bin/grep как замену для /bin/cat.

И последняя вещь. Это невероятно, насколько громадную часть системы можно удалить, не загубив её окончательно. Несмотря на тот факт, что никто бы не смог войти в систему (/bin/login?), и почти все нужные команды пропали, всё остальное выглядело нормально. Естественно, некоторые вещи не могут оставаться живы без, скажем, /etc/termcap, /dev/kmem или /etc/utmp, но, в конечном итоге, всё работает в мире и согласии.

Я оставляю вопрос: оказавшись в такой же ситуации, с возможностью мыслить, учитывая приобретённый теперь опыт, можно было бы решить эту проблему проще?

11 comments:

Denis Evsyukov said...

Были времена...
А мораль такова - не работать под рутом в консоли... Для конфигурирования системы есть sudo... Не зная пароля, не загубишь систему.
Ну а если есть среди знакомых такие "шутники", то нужно отстраивать систему безопасности типа SELinux... Дабы и rm -rf / не давало таких результатов...
Короче сейчас все намного лучше, чем было тогда... =)

アルセニ said...

rm -rf / нынче вообще не выполняется. Лично проверял на Генте и Убунте. Причём под рутом и без бэкапов. :)

Anonymous said...

А ты попробуй под рутом и без бэкапов rm -rf /*

Iv said...

В убунте выполняется, описался командой и она была интерпретирована как sudo rm -rf /*

Прекрасно работает!
Оборвал где-то в конце папки /home

Бекапы страшная сила, всем рекомендую! :)

Anonymous said...

Подобным образом на заре освоения мною юнихов тихо и печально без лишних движений восстанавливал толи фрюху то-ли линукс (не помню уже) после strip /usr/lib/*.so

Anonymous said...

Задам атипичный вопрос: а сколько они его били? И чем? И куда? И как? И с какими последствиями для здоровья?

Ingumsky said...

Хорошая история. Интересно, началось всё действительно с «пятёрки до четверга»? Я удивляюсь, что они не убили виновника своей проблемы после восстановления системы.

Anonymous said...

"Возможно, львы чего-то не договаривают" :)

Decoy said...

Wooow... Спасибо за историю! Прям окунулся в "страые-добрые"!.. ;)

Anonymous said...

А мне как-то "посчастливилось" выполнить команду chown xxx:xxx .* -R

Хотел поменять владельца скрытых файлов :) менял естественно с правами рута.

Anonymous said...

И запускал в хомдире пользователя.
Команда хорошо задумалась и я сообразил что что-то не так....

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