Я хотел бы защитить систему с помощью overlayroot, чтобы все, что делается - даже пользователем с правами root - не выдержит перезагрузки. Я нашел несколько руководств, как это сделать, но ни одно из них не говорит мне, насколько это безопасно и есть ли уловки для преодоления защиты.
Мой подход: GRUB заблокирован и предлагает только опцию overlayroot без пароля.
Но этого, скорее всего, недостаточно для защиты системы, как мог бы сделать кто-то (ну, кто-то с правами root) dd if=/dev/zero of=/dev/sda
и я предполагаю, что система откажется загружаться после перезапуска.
Согласно моим исследованиям, единственный способ ограничить root от прямого доступа /dev/sda
, /dev/sda1
и так далее - это SELinux. SELinux кажется ужасно сложным и полным излишеством только для ограничения доступа к нескольким файлам, но кажется, что это единственный способ ограничить root.
Итак, мои вопросы:
Есть ли какие-либо другие возможности для пользователя с правами root преодолеть overlayroot, кроме доступа к /dev/sda(X)
?
Есть ли другие варианты предотвращения доступа к /dev/sda(X)
а если нет, есть ли простой пример / руководство для политики SELinux, которая блокирует доступ только к определенным файлам?
Дополнение 2016-09-12:
Я нашел это: https://github.com/msuhanov/Linux-write-blocker/
Это очень маленький (7 строк кода) и простой патч ядра, который заставляет ядро Linux фактически уважать флаг только для чтения блочного устройства (в противном случае этот флаг более информативен для драйвера fs).
Это отличная отправная точка, но есть одна проблема: root может легко изменить флаг только для чтения. Моя идея сейчас:
Ядро загружается с дополнительными опциями forcero=/dev/sda forcero=/dev/sda1
В какой-то момент это анализируется, и либо существующий список блочных устройств расширяется с помощью флага только для чтения, либо создается новый список блочных устройств, доступных только для чтения.
Код из этого патча расширен для проверки наличия этого флага
Я знаю, что это не совсем безопасно, потому что какой-то специальный модуль ядра может сбросить этот флаг (за исключением того, что вы подписываете все модули и разрешаете только подписанные модули).
На самом деле я никогда не писал код ядра, первая проблема, с которой я столкнулся: мне не удалось найти определение структуры block_device
или функции bdevname
. я использовал http://lxr.free-electrons.com/ident найти, но не повезло. Моя вторая мысль: если где-то есть список, он стабилен или может его очистить повторное сканирование для устройств? Есть функция name_to_dev_t
что переводит имя как /dev/sda1
к dev_t
тип, который является просто целым числом, как это связано с block_device
?
Может кто-нибудь подсказать, как написать этот патч ядра? Я все еще открыт для других идей.
Защита системы от любых модификаций и в то же время разрешение «root» использовать полный доступ кажется проигранной битвой. Вся суть root в том, что он может делать что угодно. Как вы упомянули, вы можете вставить любой код ядра и, следовательно, получить доступ к любой области памяти, ... ко всему.
Есть два сценария: 1) вы хотите защитить от случайной записи и 2) вы хотите защитить от злонамеренной записи. Во-первых, да, такой трюк, как overlayfs, уже может защитить от большинства случайных записей. Во-вторых, запустите ненадежное программное обеспечение не как root.
Однако есть очевидный способ сделать это - просто использовать аппаратную защиту (чтобы программное обеспечение, даже root / kernel / ..) не могло писать в него. (например, запуск с компакт-диска или носителя только для чтения)
Я продлил патч, упомянутый ранее для проверки по списку блочных устройств только для чтения, настроенному в командной строке загрузки.
/*
* Block write and discard commands going to a read-only device.
* We do this because kernel drivers often lack necessary checks
* and send write/discard commands to read-only block devices.
*/
if (unlikely((bio->bi_rw & (REQ_WRITE | REQ_WRITE_SAME | REQ_DISCARD))
&& (bdev_read_only(bio->bi_bdev) || bdev_check_readonly_boot_param(bio->bi_bdev->bd_inode->i_rdev)))) {
pr_warn("unexpected %s command to %s blocked\n",
(bio->bi_rw & REQ_DISCARD) ? "discard" : "write",
bdevname(bio->bi_bdev, b));
goto end_io;
}
Это оригинальный патч, расширенный для проверки параметров загрузки с помощью этой функции:
extern dev_t READONLY_DEV[];
static inline int bdev_check_readonly_boot_param(dev_t bd)
{
dev_t *dev = READONLY_DEV;
while (*dev) {
if (*dev == bd) return 1;
dev++;
}
return 0;
}
в do_mounts.c
Я добавил это:
static char __initdata saved_readonly_dev[64]; dev_t READONLY_DEV[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; static int __init readonly_bdev_setup(char *line) { strlcpy(saved_readonly_dev, line, sizeof(saved_readonly_dev)); return 1; } __setup("forcero=", readonly_bdev_setup); /* * Setup list with read-only devices */ void __init setup_readonly_bdev(void) { int i = 0; char *dev_name, *readonly_dev; if (saved_readonly_dev[0]) { readonly_dev = saved_readonly_dev; do { dev_name = strsep(&readonly_dev, ","); if (dev_name) { READONLY_DEV[i] = name_to_dev_t(dev_name); if (READONLY_DEV[i]) { i++; printk(KERN_NOTICE "Set %s to read-only.\n",dev_name); } else printk(KERN_WARNING "Error setting read-only: Could not identify block-device '%s'\n",dev_name); } } while (dev_name); } }
Дополнительно в main.c
в функции kernel_init_freeable
Я добавил одну строку для вызова моей функции (функция объявлена в init.h
):
if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) { ramdisk_execute_command = NULL; prepare_namespace(); } setup_readonly_bdev();
Теперь вы можете загрузить ядро с аргументом командной строки forcero=8:16,8:17
и он заблокирует все вызовы записи на эти устройства. /dev/sdb
у меня не работает, функция ядра не может разрешить dev_t
-ид этого. Обратите внимание, что ядро не знает, что устройство предназначено только для чтения, вы можете писать на нем, и даже dd не сообщит вам о каких-либо проблемах, но если вы посмотрите в kern.log
, тогда вы увидите множество ошибок ввода-вывода. Если вы удалите файл в разделе только для чтения в nemo
(файловый менеджер графического интерфейса пользователя Cinnamon по умолчанию), он исчез, но затем вы нажимаете F5, и он возвращается. Также важно: Блокировка /dev/sda
не будет автоматически блокировать такие устройства, как /dev/sda1
, вы должны перечислить все блочные устройства. Но это означает, что вы можете защитить загрузочный сектор / таблицу разделов, пока некоторые разделы доступны для записи.
Я уверен, что этот патч не соответствует стандартам качества кода ядра для слияния, я был бы очень рад, если бы кто-нибудь мог его почистить / улучшить или сказать мне, что мне делать.