Технология Secure Boot нацелена на предотвращение исполнения недоверенного кода при загрузке операционной системы, то есть защиту от буткитов и атак типа Evil Maid. Устройства с Secure Boot содержат в энергонезависимой памяти базу данных открытых ключей, которыми проверяются подписи загружаемых UEFI-приложений вроде загрузчиков ОС и драйверов. Приложения, подписанные доверенным ключом и с правильной контрольной суммой, допускаются к загрузке, остальные блокируются.


Более подробно о Secure Boot можно узнать из цикла статей от CodeRush.



Чтобы Secure Boot обеспечивал безопасность, подписываемые приложения должны соблюдать некоторый «кодекс чести»: не иметь в себе лазеек для неограниченного доступа к системе и параметрам Secure Boot, а также требовать того же от загружаемых ими приложений. Если подписанное приложение предоставляет возможность недобросовестного использования напрямую или путём загрузки других приложений, оно становится угрозой безопасности всех пользователей, доверяющих этому приложению. Такую угрозу представляют загрузчик shim, подписываемый Microsoft, и загружаемый им GRUB.


Чтобы от этого защититься, мы установим Ubuntu с шифрованием всего диска на базе LUKS и LVM, защитим initramfs от изменений, объединив его с ядром в одно UEFI-приложение, и подпишем его собственными ключами.


Ограничения решений «из коробки»


Ubuntu, как и другие распространённые дистрибутивы, предлагает опцию шифрования всего диска с LVM во время установки. Дистрибутив в такой конфигурации без ошибок устанавливается на UEFI с активным Secure Boot.


Но Canonical в первую очередь заинтересована в работоспособности ОС на устройствах с включённым Secure Boot, а не в обеспечении безопасности за счёт него. Если вы хотите использовать Secure Boot как средство безопасности, то вы сами по себе.


Как Ubuntu реализует загрузку в Secure Boot с шифрованием всего диска и что с этим не так?


Red Hat разработали загрузчик shim, чтобы он работал на всех устройствах и служил на благо человечеству, соблюдая строгие предписания стандарта Secure Boot и загружая только доверенные UEFI-приложения. Canonical использует shim как прокси, встраивая в него свой публичный ключ и подписывая у Microsoft. Shim загружает GRUB, подписанный ключём Canonical, который затем загружает ядро, подписанное Canonical.


  • Начнём с того, что шифруется не весь диск — /boot остаётся незашифрованным, а значит и initramfs в нём. Доступ к initramfs означает root-доступ. Fail.


  • /boot остаётся незашифрованным, потому что устанавливаемый по умолчанию GRUB не может расшифровать диск без криптографических модулей. Которые почему-то не встроили в подписанный GRUB. GRUB'у запрещено загружать дополнительные модули в Secure Boot. Double Fail1.


  • GRUB должен верифицировать загружаемые ядра и отвергать неверно подписанные. Он этого не делает. Triple Fail.


  • GRUB загружает свои настройки из файла и по умолчанию предоставляет доступ к консоли. Подлинность конфигурационного файла не проверяется, с помощью его модификации или через консоль можно сделать что угодно: загрузить UEFI Shell, другое ядро, initramfs или передать аргументы ядру и получить root-доступ. Fatal Error2.

Что это всё означает?


Если в вашей системе есть ключ Microsoft3, то кто угодно может загрузиться с внешнего устройства, установить буткит и получить полный контроль над вашим устройством. Нет небходимости отключать Secure Boot: он уже не работает.




Согласно политике Microsoft о подписывании UEFI-приложений, все подписанные загрузчики GRUB и shim, используемые для загрузки GRUB, уже должны быть занесены в чёрный список.


Говорите, нужно просто отключить загрузку с внешних устройств? Это борьба с симптомами. Если у вас установлен незащищённый GRUB, то вас это не спасёт. Если на вашем устройстве стоит Windows, то вы можете выбрать из неё устройство для загрузки, и есть вероятность, что ваша прошивка это позволит4. Ещё остаётся PXE Network Boot. Поможет только пароль на включение устройства.


Вывод

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


Установка Ubuntu с шифрованием всего диска с помощью LUKS и LVM


LUKS — Linux Unified Key Setup — обёртка для криптографической системы dm-crypt, позволяющая создавать виртуальные зашифрованные устройства в файлах и на физических дисках. С помощью LUKS можно зашифровать данные на всём диске для того, чтобы перед загрузкой ОС требовалось ввести пароль.


LVM — Logical Volume Manager — менеджер логических томов, с помощью которого мы разделим криптоконтейнер на тома. Тома LVM автоматически монтируются после ввода пароля к криптоконтейнеру, отдельный ввод пароля для каждого тома не требуется.


Следующие инструкции должны быть применимы к любому дистрибутиву на базе Ubuntu, для других потребуются коррективы. Сперва загрузитесь с Live CD или установочного образа в режиме Try before installing.


Разметка и шифрование


Чтобы загружаться с диска в режиме UEFI, он должен быть размечен в формате GPT. Разметку диска рассмотрим с помощью KDE Partition Manager и GParted. Если у вас их нет, установите один, соответствующий вашей среде.


sudo apt-get install partitionmanager   # KDE
sudo apt-get install gparted            # GNOME и другие

Запустите редактор разделов и выберите интересующий вас диск, обычно это первый в системе — /dev/sda. Посмотрите свойства диска.


KDE Partition Manager: Два раза кликните по диску,
GParted: View -> Device Information.

В строке Partition table указана используемая таблица разделов. Если диск размечен в формате dos/msdos (MBR), то его необходимо преобразовать в GPT. Это возможно сделать без потери данных, но здесь я этого описывать не буду, поищите инструкции в интернете. Если на диске нет важных данных и вы хотите форматировать его в GPT, создайте новую таблицу.


KDE Partition Manager: New Partition Table — GPT
GParted: Device -> Create Partition Table — gpt

На диске должен быть как минимум один раздел ESP (EFI System Partition), в котором будут храниться загрузчики. Если на этом диске установлена ОС в режиме UEFI, то один такой раздел уже есть. В любом случае я рекомендую создать новый размером не меньше 100 МБ. ESP должен быть отформатирован в один из FAT-форматов, предпочтительно в FAT32, а также помечен как загрузочный.


KDE Partition Manager: Кликнуть по неразмеченной области -> New
    File system: fat32
    Size: 128.00 MiB
    Free space before: 0.00 — место после таблицы GPT
    OK, Apply
    Выбрать созданный раздел и открыть свойства (Properties), выставить флаг boot
    OK, Apply

GParted: Кликнуть по неразмеченной области -> New
    File system: fat32
    New size: 128 MiB
    Free space preceding: 1 MiB или больше — место под таблицу GPT
    Add, Apply
    Выбрать созданный раздел и открыть управление флагами (Manage Flags), выставить флаг boot
    Close

Дальше нужно создать раздел для шифрования. Тем же образом, что и ESP, только без форматирования (unformatted), выставления флагов и размером побольше — так, чтобы вместил систему и раздел подкачки. Создадим в этом разделе криптоконтейнер LUKS через терминал, предварительно перейдя в режим суперпользователя.


sudo -i

Отформатируем раздел с указанием современных алгоритмов шифрования и хеширования. В режиме XTS длину ключа необходимо указывать в два раза больше, поэтому для AES-256 нужно указать ключ длиной 512 бит. Параметр --iter-time задаёт время в миллисекундах, затрачиваемое на генерацию ключа из вводимого пароля функцией PBKDF2. Большее количество итераций усложняет перебор пароля, но и увеличивает время ожидания после ввода верного пароля.


cryptsetup luksFormat --cipher aes-xts-plain64 --key-size 512 --hash sha512 --iter-time 2000 /dev/sda2

Подтвердите форматирование, написав YES, введите пароль. Теперь откройте криптоконтейнер (sda2_crypt — имя для маппинга) и введите тот же пароль.


cryptsetup luksOpen /dev/sda2 sda2_crypt

Контейнер должен стать доступным как блочное устройство /dev/mapper/sda2_crypt. Перейдём к разметке логических томов внутри криптоконтейнера. Инициализируем физический раздел LVM поверх /dev/mapper/sda2_crypt.


pvcreate /dev/mapper/sda2_crypt

Внутри этого физического раздела создадим группу томов с именем ubuntu.


vgcreate ubuntu /dev/mapper/sda2_crypt

Теперь мы можем создавать логические тома внутри этой группы. Первым делом создадим том для раздела подкачки и инициализируем его. Рекомендуемый размер — от sqrt(RAM) до 2xRAM в гигабайтах.


lvcreate -n swap -L 4G ubuntu # создать логический том с меткой swap размером 4 ГБ в группе ubuntu
mkswap /dev/ubuntu/swap

Добавим том для корня и создадим в нём файловую систему ext4. Хорошей практикой считается оставлять свободное место и расширять тома по мере необходимости, поэтому выделим для корня 20 ГБ. По желанию в свободном месте можно будет разметить дополнительные тома для home, usr, var и так далее. Выделить всё свободное место для тома можно с помощью параметра -l 100%FREE.


lvcreate -n root -L 20G ubuntu
mkfs.ext4 /dev/ubuntu/root

С разметкой закончено, можно перейти к установке.


Установка


Так как мы планируем создать загрузчик самостоятельно, да и установщик Ubuntu не поддерживает шифрование /boot, запустим установку без создания загрузчика.


ubiquity -b

На этапе разметки диска выберите Вручную.


Здесь нам необходимо указать точки монтирования. Выберите /dev/mapper/ubuntu-root, укажите использование в качестве журналируемой файловой системы Ext4, точку монтирования (Mount Point) в /, без форматирования. Ubiquity сама подхватит /dev/mapper/ubuntu-swap как раздел подкачки и запомнит один из системных разделов EFI. Экран разметки должен выглядеть так:




Закончите установку и не перезагружайтесь.


Настройка crypttab, fstab и resume


Смонтируйте корень установленной системы в /mnt, свяжите /dev, /sys и /proc с /mnt/dev, /mnt/sys и /mnt/proc соответственно, а также /etc/resolv.conf с /mnt/etc/resolv.conf, чтобы у вас был доступ к сети. Теперь смените корневой каталог с помощью chroot.


mount /dev/ubuntu/root /mnt
mount --bind /dev /mnt/dev
mount --bind /sys /mnt/sys
mount --bind /proc /mnt/proc
mount --bind /etc/resolv.conf /mnt/etc/resolv.conf
chroot /mnt
mount -a # смонтировать ESP раздел в /boot/efi автоматически, если он записан установщиком в /etc/fstab

Вам необходимо вручную заполнить /etc/crypttab — файл, описывающий монтируемые при загрузке криптоконтейнеры.


nano /etc/crypttab

В него нужно добавить запись о /dev/sda2, монтируемом в /dev/mapper/sda2_crypt. Настроим монтирование по UUID, а не по имени устройства. Чтобы узнать UUID /dev/sda2, откройте другой терминал и воспользуйтесь командой:


sudo blkid

В строке, начинающейся с /dev/sda2, будет записан его UUID. Скопируйте его (Ctrl+Shift+C). В /etc/crypttab добавьте запись вида имя_маппинга UUID=<UUID> none luks, вставив UUID (Ctrl+Shift+V). Закройте nano, нажав Ctrl+X и Y, подтвердив сохранение.




Проверьте, чтобы в /etc/fstab были правильно описаны монтируемые разделы, а в /etc/initrmfs-tools/conf.d/resume указан раздел для пробуждения из гибернации.




После всех изменений обновите образ initramfs.


update-initramfs -u

Не выходите из системы и chroot,


Создание загрузчика


Ядро Linux поддерживает загрузку напрямую из UEFI, если оно было скомпилировано с параметром CONFIG_EFI_STUB. В таком случае initramfs обычно хранится рядом в ESP, и путь к нему передаётся в аргументах к ядру.


Однако отсутствие верификации initramfs позволяет встроить в него вредоносный код, имея доступ на запись в ESP. Teddy Reed предлагает компилировать ядро, встраивая в него initramfs.


Процесс компиляции ядра достаточно длительный, её придётся производить после каждого изменения initramfs. К счастью, есть другой способ. В пакете systemd (ранее в gummiboot) находится linuxx64.efi.stub — заготовка UEFI-приложения, в которую можно встроить ядро, initramfs и аргументы, передаваемые ядру. Подписав это UEFI-приложение, мы защитим ядро и initramfs от изменений.


Для данной операции потребуется пакет binutils.


sudo apt-get install binutils

Запишем в /tmp/cmdline аргументы, которые будут передаваться ядру.


echo -n "quite splash" > /tmp/cmdline

В /boot хранятся образы ядра (vmlinuz-*-generic) и initramfs (initrd.img-*-generic). Определите последнюю версию и встройте их в заготовку.


objcopy   --add-section .osrel=/etc/os-release --change-section-vma .osrel=0x20000   --add-section .cmdline=/tmp/cmdline --change-section-vma .cmdline=0x30000   --add-section .linux=/boot/vmlinuz-4.4.0-34-generic --change-section-vma .linux=0x2000000   --add-section .initrd=/boot/initrd.img-4.4.0-34-generic --change-section-vma .initrd=0x3000000 /usr/lib/systemd/boot/efi/linuxx64.efi.stub ubuntu.efi

Полученное UEFI-приложение ubuntu.efi необходимо расположить в ESP в каталоге EFI/BOOT/. Установщик Ubuntu должен был определить ESP и настроить монтирование в /boot/efi. Если в этом ESP нет других загрузчиков, то ubuntu.efi можно скопировать в /boot/efi/EFI/BOOT/BOOTX64.EFI, тогда он будет загружаться при выборе этого раздела в меню загрузки UEFI.


mkdir -p /boot/efi/EFI/BOOT
cp ubuntu.efi /boot/efi/EFI/BOOT/BOOTX64.EFI

Если в ESP уже записан загрузчик BOOTX64.EFI, то можно создать ещё один ESP, либо записать ubuntu.efi под другим именем и добавить соответствующую загрузочную запись через встроенную в вашу прошивку консоль UEFI (UEFI Shell). Использование efibootmgr не рекомендовано5.


UPD: Если в вашу прошивку не встроен UEFI Shell, то скачать его можно отсюда. Положите его в EFI/BOOT/BOOTX64.EFI любого ESP и загружайтесь с отключённым Secure Boot. Чтобы добавить загрузочную запись, введите команду:


bcfg boot add 0 fs0:\EFI\BOOT\UBUNTU.EFI
# 0 -- номер строки в загрузочном меню, в которую будет добавлена запись
# fs0 -- первая файловая система, может быть другой
# Положить загрузчик можно и в корень ESP, тогда указать путь \UBUNTU.EFI

Спасибо Prototik за ссылку на UEFI Shell. Список остальных команд можно найти здесь.


Если у вас включён Secure Boot, то загрузиться с ubuntu.efi не получится, так как он не подписан. Временно отключите Secure Boot и загрузитесь, либо продолжите из chroot.


Настройка Secure Boot


Генерацию ключей, их установку в прошивку и подписывание UEFI-приложений описал CodeRush здесь, поэтому я буду считать, что вы всё понимаете и умеете.


Остаётся только подписать созданный нами загрузчик.


sbsign --key ISK.key --cert ISK.pem --output BOOTX64.EFI ubuntu.efi

Поместите BOOTX64.EFI в каталог EFI/BOOT/ раздела EFI, с которого вы планируете загружаться.


Автоматизация


Чтобы загрузчик автоматически обновлялся и подписывался при обновлении initramfs, создайте скрипт update-efi-loader в /etc/initramfs/post-update.d/, изменив пути где требуется.


echo -n "quiet splash" > /tmp/cmdline

objcopy   --add-section .osrel=/etc/os-release --change-section-vma .osrel=0x20000   --add-section .cmdline=/tmp/cmdline --change-section-vma .cmdline=0x30000   --add-section .linux=/boot/vmlinuz-$(uname -r) --change-section-vma .linux=0x2000000   --add-section .initrd=/boot/initrd.img-$(uname -r) --change-section-vma .initrd=0x3000000 /usr/lib/systemd/boot/efi/linuxx64.efi.stub /tmp/ubuntu.efi

sbsign --key /root/keys/ISK.key --cert /root/keys/ISK.pem --output /boot/efi/EFI/BOOT/BOOTX64.EFI /tmp/ubuntu.efi

Дайте скрипту право на исполнение.


chmod a+x /etc/initramfs/post-update.d/update-efi-loader

При обновлении ядра придётся произвести эту операцию вручную.


Подписывание драйверов и модулей ядра


Если вам нужно установить сторонние или собственные драйвера и модули ядра, их необходимо подписать. Для подписи модулей ядра требуются сертификат в формате DER и ключ без пароля, то есть сгенерированный с параметром -nodes.


openssl req -new -nodes -utf8 -sha256 -days 36500 -batch -x509        -subj "/CN=Kernel Key" -outform DER -out kernel.der        -keyout kernel.key

Для подписывания используется скрипт sign-file.


/usr/src/linux-headers-$(uname -r)/scripts/sign-file sha256 kernel.key kernel.der module.ko

Чтобы добавить этот сертификат в прошивку, его необходимо преобразовать в формат PEM, затем в ESL и подписать ключом KEK.


openssl x509 -inform der -in kernel.der -outform pem -out kernel.pem
cert-to-efi-sig-list -g "$(uuidgen)" kernel.pem kernel.esl
sign-efi-sig-list -k KEK.key -c KEK.pem kernel kernel.esl kernel.auth

Очевидные советы


Если вашей задачей стоит защита данных на устройстве, то Secure Boot выполнит свою работу и не больше. Остальное возлагается на вас.


  • Не добавляйте чужих ключей в прошивку. Даже от Microsoft. В первую очередь от Microsoft.


  • Не подписывайте UEFI Shell, KeyTool или другие приложения, имеющие доступ к записи в NVRAM. Используйте их в Setup Mode.


  • Не оставляйте устройство включённым без присмотра. Устройство в ждущем режиме (suspend to RAM) содержит в RAM расшифрованные данные и мастер-ключи от криптоконтейнеров.


  • Установите пароль на UEFI Setup не проще, чем от вашего криптоконтейнера.


  • При физическом доступе к внутренностям устройства можно отключить Secure Boot, сбросив память NVRAM или повредив её, а также оставить хардварную закладку. Такая атака успешна только тогда, когда она незаметна. Сделайте так, чтобы вы о ней могли узнать: заклейте винты на корпусе трудновоспроизводимыми стикерами, обмажьте их лаком с блёстками. Опечатайте своё устройство.


  • Поставьте первым в списке загрузки неподписанное приложение. Если вы однажды не увидите сообщение от Secure Boot, то ваше устройство однозначно скомпрометировано.


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

Бонус: возвращение гибернации


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


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




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


Chung-Yi Lee ещё в 2013 предложил верифицировать образ восстановления, а в 2015 представил реализующий его идею патч. Но воз и ныне там. Поэтому предположим, что мы достаточно защищены с нашим шифрованием, и вернём нам гибернацию без верификации.


Способ 1. Отключить верификацию модулей ядра


Включённая верификация модулей ядра отключает гибернацию. По умолчанию верификация модулей ядра включается вместе с Secure Boot, однако она от Secure Boot не зависит. Её можно отключить, оставив только Secure Boot.


Большого ущерба безопасности это нанести не должно. Модули ядра устанавливаются из доверенного источника вместе с обновлением ядра и хранятся на зашифрованном диске и в верифицируемом initramfs. Сторонние драйвера устанавливаются вручную, и будут они подписаны нами или нет, значения не имеет, ведь мы им уже доверяем. SecureApt для ядра и TLS/HTTPS для сторонних драйверов должны защитить от MiTM, и тогда остаётся только root-доступ к расшифрованному диску. Но в таком случае у злоумышленника уже есть наши данные.


«Оставить заявку» на отключение верификации модулей можно с помощью mokutil, а подтвердит её загрузчик shim.


sudo apt-get install mokutil shim
sudo mokutil --disable-validation

Введите пароль, который затем потребуется посимвольно подтвердить. Теперь нужно загрузиться через shim и выбрать в нём Change Secure Boot state (sic!). Поместите /usr/lib/shim.efi в EFI/BOOT/BOOTX64.EFI на одном из ESP или добавьте загрузочную запись через UEFI Shell. Предварительно отключите Secure Boot, после верните обратно.



Сейчас Secure Boot и гибернация работают, UEFI-приложения верифицируются, но модули ядра нет.


В принципе, shim и mokutil больше не требуются, их можно удалить.


Способ 2. Использовать старую версию ядра


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


Способ 3. Скомпилировать своё ядро


Если ваше время ничего не стоит, то вы можете скомпилировать своё ядро без этого ограничения. Гарантий, что после долгих мучений вы будете довольны результатом, нет. Но если вы этого очень хотите, хвала Линусу Торвальдсу и GPLv2, у вас есть на это право. Вы можете предварительно протестировать скомпилированное мною ядро, чтобы не тратить зря время.


Инструкции

Получение исходного кода


apt-get

Самый простой способ получить исходный код для ядра вашей версии — скачать его из репозитория.


В /etc/apt/sources.list должны присутствовать указатели на репозитории исходных кодов. Обычно там уже есть закомменти­рованные записи с deb-src. Раскомментируйте их для репозиториев xenial main и xenial-security main, либо добавьте сами, а затем обновите индекс apt.


$ sudo nano /etc/apt/sources.list
...
deb-src http://ru.archive.ubuntu.com/ubuntu/ xenial main restricted
deb-src http://security.ubuntu.com/ubuntu xenial-security main restricted
...
$ apt-get update

Загрузите исходный код и перейдите в создавшуюся директорию.


apt-get source linux-image-$(uname -r)
cd linux-4.4.0

Обратите внимание на то, чтобы apt скачивал актуальную версию исходного кода. Проверьте номер версии у файла .dsc.


linux_4.4.0-34.53.dsc

git

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


Установите git.


sudo apt-get install git

Создайте локальную копию git-репозитория ядра текущего релиза Ubuntu и перейдите в создавшуюся директорию.


git clone git://kernel.ubuntu.com/ubuntu/ubuntu-xenial.git
cd ubuntu-xenial

По умолчанию git указывает на ветку master, соответствующую версии последнего релиза. Переключиться на другую версию можно по тегу релиза этой версии. Чтобы перечислить все теги по заданной маске, используйте git tag -l <маска>.


$ git tag -l Ubuntu-*
...
Ubuntu-4.4.0-33.52
Ubuntu-4.4.0-34.53
Ubuntu-4.4.0-35.54
...

Создайте ветку temp для тега, соответствующего вашей версии, и переключитесь на неё.


git checkout -b temp Ubuntu-4.4.0-34.53

Настройка


Загрузите пакеты, требуемые для компиляции (build dependencies).


sudo apt-get build-dep
sudo apt-get ccache fakeroot kernel-package libncurses5-dev

Убедитесь, что скриптам выставлено право на исполнение, запустите чистку.


chmod a+x debian/rules
chmod a+x debian/scripts/*
chmod a+x debian/scripts/misc/*
fakeroot debian/rules clean

Скопируйте старый файл конфигурации в текущую директорию, запустите конфигурацию, выберите Load и загрузите config. Больше изменять ничего не требуется, выйдите и сохраните конфигурацию — Exit > Yes.


cp /boot/config-4.4.0-34-generic config
fakeroot debian/rules editconfigs

Измените файл kernel/power/hibernate.c, убрав проверку secure_modules().


--- a/kernel/power/hibernate.c
+++ b/kernel/power/hibernate.c
@@ -67,7 +67,7 @@ static const struct platform_hibernation_ops *hibernation_ops;

 bool hibernation_available(void)
 {
-   return ((nohibernate == 0) && !secure_modules());
+   return (nohibernate == 0);
 }

 /**
--

Если вы используете git

Подготовьте файл к коммиту.


git add kernel/power/hibernate.c

Если вы ещё не совершали коммитов и не вводили свои данные, сделайте это сейчас.


git config --global user.email "you@example.com"
git config --global user.name "Your Name"

Сделайте коммит, введите комментарий.


$ git commit
...
Allow hibernation on Secure Boot

Теперь ваши изменения сохранены в новом снимке состояния (snapshot). Если вы захотите обновиться до следующей версии и применить к ней те же самые изменения, используйте git rebase <ветка или тег>


$ git rebase Ubuntu-4.4.0-35.54
Сначала перематываем указатель текущего коммита, чтобы применить ваши изменения поверх него…
Применение: Allow hibernation on Secure Boot

Скрипты компиляции определяют версию ядра по последней записи в истории изменений (changelog) в директории debian.master. Добавьте новую запись, чтобы изменить версию.


EDITOR=nano debchange -c debian.master/changelog -l "custom"

К версии будет добавлен суффикс custom1, что отразится при сборке пакетов .deb и позволит установить их при уже установленных пакетах той же версии без суффикса. Однако этот суффикс распространяется только на имя пакета, но не на его содержимое: ядро и директория с его модулями будут иметь ту же версию 4.4.0-34-generic, и при установке старые файлы перезапишутся новыми. Чтобы этого избежать, измените версию ABI c 34 на, например, 3400.


linux (4.4.0-3400.53custom1) UNRELEASED; urgency=medium

  * Allow hibernation on Secure Boot
...

Компиляция


Запустите чистку ещё раз и скомпилируйте ядро. Если вы не опытный разработчик ядра и не понимаете, как работают проверки ABI и модулей (я вот не понимаю), отключите их (skipabi=true, skipmodule=true), иначе ваша компиляция сломается на одном из последних этапов. Здесь используется многопоточная сборка пакетов с количеством потоков, равным количеству ядер процессора. Цель binary-generic означает компиляцию обычной разновидности ядра, архитектура определяется автоматически.


fakeroot debian/rules clean
skipabi=true skipmodule=true DEB_BUILD_OPTIONS=parallel=$(getconf _NPROCESSORS_ONLN) do_tools=false no_dumpfile=1 fakeroot debian\rules binary-generic

Если компиляция прошла успешно, то в вашей домашней директории появятся три пакета .deb. Необходимо установить linux-image-<version>.deb, а также желательно linux-image-extra-<version>.deb. Это можно сделать с помощью dpkg -i <путь к пакету> или через QApt, открыв пакет в файловом менеджере, если он это поддерживает. Будьте осторожны: если вы не изменяли версию ABI, то старое ядро и модули перезапишутся.


Снова соберите загрузочный файл.


echo -n "quiet splash" > /tmp/cmdline

objcopy   --add-section .osrel=/etc/os-release --change-section-vma .osrel=0x20000   --add-section .cmdline=/tmp/cmdline --change-section-vma .cmdline=0x30000   --add-section .linux=/boot/vmlinuz-4.4.0-34-generic --change-section-vma .linux=0x2000000   --add-section .initrd=/boot/initrd.img-4.4.0-34-generic --change-section-vma .initrd=0x3000000 /usr/lib/systemd/boot/efi/linuxx64.efi.stub /tmp/test.efi

sbsign --key /root/keys/my.key --cert /root/keys/my.pem --output /boot/efi/EFI/BOOT/BOOTX64.EFI /tmp/test.efi


Гибернация работает, но нестабильно. Как, впрочем, и без Secure Boot.


Способ 4. Отказ от гибернации и использование виртуализации


Если гибернация и работает, то это не делает её надёжным средством сохранения состояния. Это может быть проблемой моего железа, дистрибутива или, что более вероятно, KDE Plasma, но у меня Kubuntu просыпается через раз.


По уже описанной технологии в качестве хостовой ОС можно установить подходящий дистрибутив Linux, а гостевой — предпочитаемую для работы. При завершении работы автоматически останавливать виртуальную машину с сохранением состояния, а затем отключать устройство. При включении же восстанавливать состояние. Если ваше устройство поддерживает аппаратную виртуализацию, то для этого подойдёт Qemu KVM. Но это уже тема для отдельной статьи.


С большей надёжностью придёт и большая защищённость: чувствительные данные можно изолировать от опасной среды. Браузер и песочница для установки стороннних пакетов в одной виртуальной машине, важные персональные данные — в другой. Украсть мастер-ключ от зашифрованного диска в памяти хостовой ОС из гостевой гораздо сложнее. Кажется, для подобного существует Qubes OS. Но она данный момент не поддерживает Secure Boot. Fail.


На этом всё, приветствуются любые дополнения и замечания.


Примечания


  1. ^Решаемо путём сборки образа GRUB с нужными модулями с помощью grub-mkstandalone, но его придётся подписывать самому.


  2. ^Теоретически можно исправить, установив пароль, встроив grub.cfg в образ GRUB с помощью grub-mkstandalone и установив в grub.cfg prefix на невалидный путь, чтобы GRUB не мог найти второй grub.cfg на диске. Но опять же требуется подписывать образ самостоятельно.


  3. ^А он есть у всех кроме параноиковоправданно озабоченных своей безопасностью пользователей.


  4. ^У меня загрузиться с USB не даёт. Windows 8 и 10 также без пароля не пускают в безопасный режим или консоль.


  5. ^Говорят, некоторые прошивки он окирпичивает. Безопаснее создать по ESP на каждый загрузчик.
Поделиться с друзьями
-->

Комментарии (26)


  1. Meklon
    18.08.2016 13:16
    +11

    Полный восторг. Хабр — торт. Редко попадается такой уровень публикаций) спасибо.


  1. aardvarkx1
    18.08.2016 14:48

    Отличная статья. Спасибо.


  1. hdfan2
    18.08.2016 15:03

    Очень круто. Жалко только, что для такой достаточно полезной вещи приходится столько приседать, вместо того, чтобы щёлкнуть чекбокс при инсталляции.


  1. Ivan_83
    18.08.2016 15:27
    +3

    Всё хорошо, только вот какие основания у вас доверять UEFI и прочему коду вшитому в железо?
    А если нет доверия UEFI то вся цепочка теряет смысл.


    1. Hellishnoob
      18.08.2016 18:15
      +5

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

      Если вы имеете в виду намеренно оставленные закладки, то здесь нужно учесть область применения Secure Boot и взвесить важность вашей информации против стоимости атаки на неё. Эффективно используя Secure Boot, вы ограничиваете круг противников (adversary) до тех, кто способен использовать эти закладки, значительно увеличивая стоимость атаки. Как мне кажется, для ноутбука с личными данными такой защиты достаточно. Для информации, вызывающей острый интерес иностранных служб разведки, наверное, нет.

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


      1. Ivan_83
        19.08.2016 20:18
        +1

        Признайте уже что:
        — обычным хакерам и школоте тема с бутом вообще не интересна: это трудно и долго вникать, возможностей мало
        — обычному хакеру и даже школоте много проще накидать батник или софтину на си/дельфи/… которая пропишется в автозагрузку и обеспечит удалённый доступ и управление и зашифрует файлы и попросит выкуп
        — на практике можно по пальцам пересчитать тех зловредов и инструменты которые гадят в бут (особенно если выкинуть все эпохи DOS, тогда это было любимое развлечение)
        — от секуребута больше всего выиграли мс и яблоко: в случае мс можно не только продавать вендорлок железки но и мешать работе кряков которые через бутлоадер пишут в теневую копию биоса слик таблицы, заодно можно не беспокоится что юзер загрузит свой драйвер и украдёт дрм контент
        — если речь про целевую атаку и задачу закрепится в системе то опять же сильно проще определить привычки цели, софт, документы и сделать так чтобы они и на чистой системе догружали и устанавливали всё, ну и опять же венда при сетупе может легко затереть бут под себя

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

        Я вижу только профиты корпораций:
        — краткосрочно: мс откусила ещё кусочек тех кто не хотел платить и ставил кряки винды в бут
        — краткосрочно: производители железа неплохо поднялись с UEFI — теперь то матери гарантированно будут дохнуть года через 2-4 затирая флешку до дыр.
        — может быть в среднесрочной перспективе риски цифрового тоталитаризма: когда производители железа и софта вступят в сговор и будут требовать плату за пользование.

        Насчёт сговора я уверен что он уже состоялся у интела и мс: слишком много никому ненужных секурефич интел понаписал в последние процы. Никому кроме мс и всяких копирастов.

        Ещё раз: в чём польза простому юзеру от секуребута?
        И чего это вы 5 лет молчали и тут вдруг начали с евангелизма секуребута?


        1. Hellishnoob
          19.08.2016 23:02
          +2

          > имея физ доступ секуребут вообще ни разу не проблема, даже на элементарном уровне, без реверса и хакинга: покупаем такую же железку, перетыкаем винт с модифицированным загрузчиком и всё

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

          > Ещё раз: в чём польза простому юзеру от секуребута?

          Пользователю, который не шифрует свои данные, пользы от него нет. Для себя я пользу нашёл — в качестве защиты от атаки Evil Maid. Если вы считаете, что в таком качестве он непригоден, объясните. Остальное офтопик.


          1. Ivan_83
            20.08.2016 20:45

            А смысл?
            Жучёк на клаву прост и дёшев, опытный человек поставит его ещё быстрее чем возится с подменой бута.
            В случае стационарных компов всё сильно проще: можно просто воткнутся снаружи и очень долго оставаться незамеченным, как в той библиотеке было.

            Те для имеющего физ доступ секуребут ни разу не преграда чтобы получить пароль для работы с диском.

            Всё остальное — намного важнее секуребута типа для пользы юзера, будем считать соскок с темы подтверждением злонамеренного евангелизма в этой области.


  1. darkrain
    18.08.2016 16:02

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

    Насчет доверия к uefi, есть вообще какие либо альтернативы? Допустим я могу прошить свой чип с биосом.


    1. JerleShannara
      18.08.2016 16:38
      +1

      CoreBoot и его полностью обезблобленный форк LibreBoot. Но поддерживаемое железо вас расстроит. Плюс если вы не хотите бинарных модулей, то всё от интела старше Core 2 Duo вам не подойдет. С амд чутка лучше, но всёравно, как появляется PSP так исчезает agesa в исходниках. SecureBoot там нет, но в случае использования только линукса он становится ненужным — можно грузить ядро напрямую (FILO) либо всунуть его в образ прошивки.


    1. KonstantinSpb
      18.08.2016 16:48

      Гуглите open source uefi
      https://www.coreboot.org/
      http://www.tianocore.org/
      https://libreboot.org/


  1. CodeRush
    18.08.2016 18:06
    +1

    Отличная статья, спасибо.

    Поправлю немного по примечаниям:
    4. Выбрать загрузочное устройство в  Windows 8 и Windows 10 очень просто, даже не имея пароля. На стартовом экране есть кнопка Power, которая открывает меню с Power off/Standby/Restart. Если нажать на Restart удерживая Shift, вместо перезагрузки произойдет переход в меню Troubleshooting, откуда можно перейти сначала на Advanced Settings, а затем и на Startup Settigs, где и выбрать следующее загрузочное устройство. Пишу по памяти и не имею сейчас доступа к машине с Windows, но когда я пробовал вышеописанное в последний раз пару месяцев назад — работало.
    5. Лучше не создавать больше одного ESP (и не создавать ESP меньше 200 Мб, ограничение не жесткое, но некоторым старым загрузчикам не нравится), а просто сложить все загрузчики на один раздел. Efibootmgr действительно лучше не пользоваться, а вот UEFI Shell намного чаще приходится загружать с внешнего носителя, т.к. встраивать его себе в прошивку — потенциальная проблема безопасности, и потому не очень рекомендуется.

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


    1. Hellishnoob
      18.08.2016 18:34
      +2

      Спасибо за замечания.

      4. Я об этом способе и говорю, пароль не нужен. У меня Windows передаёт команду на загрузку устройства UEFI, а в нём загрузка с USB отключена, поэтому загрузка не срабатывает. Не исключено, что раньше Windows делала это как-то по-другому, или моя прошивка не имеет такой уязвимости. Из вашей же статьи о нём и узнал.

      5. Откуда можно стянуть UEFI Shell? Добавил бы ссылку в статью. В гугле находятся бинарники неизвестного происхождения. В вики Ubuntu вообще написано: «Если вы ставили Ubuntu на чистый диск, а в прошивке нет встроенного UEFI shell, то его можно доставить руками. Сам бинарный файл легко находится через любой поисковик».


      1. Prototik
        18.08.2016 19:44
        +2

        Откуда можно стянуть UEFI Shell?

        Я пользуюсь шеллом из состава Tianocore EDK2
        Для арча есть пакетик в AUR'e, для остальных ОСей не знаю, к сожалению, но можно собрать ручками по аналогии. Либо взять бинарную сборку из репы.


  1. zhigalin
    18.08.2016 18:35

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

    Не, она нацелена на поддержание vendor lock-in от Mi©ro$oft

    Кстати, а что делать если система перестанет загружаться по какой-то причине?
    Чрут с live cd уже не сделать…


    1. Hellishnoob
      18.08.2016 18:48
      +2

      Временно отключить Secure Boot до исправления проблемы. Если потребуется изменить ключи, то снова перевести в Setup Mode.


  1. grossws
    18.08.2016 21:15
    +1

    трюк с /tmp/cmdline вполне можно сделать и без временного файла:


    CMDLINE="quiet nosplash"
    
    objcopy   --add-section .cmdline=<(echo $CMDLINE) --change-section-vma .cmdline=0x30000
      # etc

    Хотя ничего критичного нет, всё равно выполняется на доверенной системе.


  1. kay
    18.08.2016 21:59

    Статья почти слово в слово повторяет мою запись в личной wiki. Мне порой кажется, что если я что-то подобное опубликую, то в меня полетит критика в роде "капитан очевидность" или "задрот".


    У меня вопрос к следующей фразе:


    Однако отсутствие верификации initramfs позволяет встроить в него вредоносный код, имея доступ на запись в ESP. Teddy Reed предлагает компилировать ядро, встраивая в него initramfs.

    Как это может быть, если initramfs находится на зашифрованном разделе (а не на ESP), а grub при загрузке сначала запросит пароль перед тем как считать initramfs и ядро с зашифрованного диска. Зачем нужна морока со сборкой и подписью своего ядра?


    На ESP в моём случае находится лишь только grubx64.efi


    1. kay
      18.08.2016 22:14
      -1

      В сноске 2 как раз правильное решение используется.


      Теоретически можно исправить, установив пароль, встроив grub.cfg в образ GRUB с помощью grub-mkstandalone и установив в grub.cfg prefix на невалидный путь, чтобы GRUB не мог найти второй grub.cfg на диске. Но опять же требуется подписывать образ самостоятельно.


      1. Hellishnoob
        18.08.2016 22:27

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


    1. Hellishnoob
      18.08.2016 22:23

      У вас GRUB работает в Secure Boot с шифрованием /boot? Если initramfs находится в зашифрованном разделе, а у GRUB заблокированы консоль и загрузка конфигурации из файла, в нём нельзя изменить передаваемые ядру параметры при загрузке, то дополнительно защищать initramfs не нужно. В противном случае его можно подменить.


  1. kay
    18.08.2016 22:20

    UEFI secure boot кстати вполне спокойно работает на MBR (не могу точно сказать насколько это соответствует стандарту, давно проблему решал). Только необходимо osprober пофиксить https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=817023


  1. AVX
    19.08.2016 23:56
    -1

    Не оставляйте устройство включённым без присмотра. Устройство в ждущем режиме (suspend to RAM) содержит в RAM расшифрованные данные и мастер-ключи от криптоконтейнеров

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


    1. KonstantinSpb
      20.08.2016 01:17

      Cold boot attack
      https://ru.wikipedia.org/wiki/Cold_boot_attack


      1. AVX
        20.08.2016 08:21

        Статья не вызывает доверия. Большая часть ссылок в ней уже мертва, и датируются они 2002-2011гг. Чуть больше информации в англоязычной, но ссылки… то же самое.
        https://en.wikipedia.org/wiki/Cold_boot_attack
        Но в целом суть я понял, спасибо.


        1. AVX
          20.08.2016 21:24

          Видимо, кто-то не понял. Я говорю про статью в википедии (рус.) https://ru.wikipedia.org/wiki/Cold_boot_attack