Тео де Раадт предложи включването на нов механизъм в OpenBSD за намаляване на повърхността на атака, реализиран чрез разширяване на възможностите за системния повик openat. Патчовете с реализирането на допълнителни флагове за openat и open, които ограничават възможността за преминаване към горните директории чрез \/.. и достъпа чрез абсолютни пътища, са подготвени за ядрото, libc и някои приложения от базовата система. Измененията все още не са включени в OpenBSD-current и са в етап на обсъждане между разработчиците.
Семейството на системните повиквания openat(2) работи като аналог на open(2), с изключение на това, че ако в параметъра 'path' е указан относителен път, отваряният файл се определя относно директорията, свързана с файловия дескриптор 'fd', а не с текущата работна директория. Ако се предаде абсолютен път на openat, например: int dirfd = open('/tmp', O_RDONLY | O_DIRECTORY); int hfd = openat(dirfd, '/etc/hosts', O_RDONLY);
функцията openat() ще игнорира 'dirfd' и, следователно, абсолютният път ще бъде обработен по обикновен начин.
Следователно, замяната на open() с openat() сама по себе си не повишава безопасността на програмата. Този повик може да ускори анализа на пътя, но не ограничава достъпа до файловата система. Флаговете, които забраняват абсолютни пътища (например, RESOLVE_BENEATH и /или RESOLVE_IN_ROOT за openat2 в Linux), също не гарантират защита: програмистът трябва да ги добавя към всички подходящи повици, а при овладяване на контрола на процеса атакуващият може да използва други пътища за отваряне на файлове.
По време на работа над утилитата openrsync, Тео се нуждаеше от ограничаване на възможностите й за обход на файловата система, но не можеше да направи това чрез функциите unveil() и pledge(). Тогава се роди идеята за механизъм, подобен на openat(), но със свойства на безопасност, допълващи pledge/unveil или дори работещи при тяхната липса.
Основната идея е да се направят ограничения част от самия дескриптор на директорията. За това се предлага флагът F_BELOW, който може да се зададе чрез fcntl(), или флагът O_BELOW за open(). Ограниченият по този начин дескриптор „dirfd“ ще позволява само преминаване надолу в дървото на директориите: повикванията openat() с абсолютен път или с преминаване нагоре чрез „..“ ще завършват с грешка ENOENT. При атака, водеща до изпълнение на код, таблицата с файловите дескриптори на процеса ще съдържа по-малко функционални „dirfd“, което ще ограничи повърхността на атаката.
Източник: opennet.ru
