Файловые разрешения в Linux

Всем привет. Мы активно вливаемся в работу и уже в январе готовим много мощных запусков. Среди прочих, объявлен набор на новый поток полюбившегося всем курса «Администратор Linux». В преддверии запуска традиционно делимся переводом полезного материала.

Файловые разрешения в Linux

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


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

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

Разрешения отлично подходят для сервисов, которые обычно всегда запускаются от имени root-пользователя, но как насчет утилит командной строки? К счастью, это так же поддерживается при условии, что у вас установлены правильные утилиты. Если вы используете Ubuntu, вам, например, понадобится пакет libcap2-bin. Вам также нужно будет запустить не архаичное ядро (начиная с версии 2.6.24).

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

Первый шаг — выбрать нужные вам разрешения. Для этой статьи я предполагаю, что существует инструмент диагностики сети, называемый tracewalk, который должен уметь использовать необработанные сокеты. Обычно для этого требуется, чтобы приложение запускалось от имени root-пользователя, но при просмотре списка выясняется, что требуется только разрешение CAP_NET_RAW.

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

sudo setcap cap_net_raw=eip tracewalk

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

setcap -v cap_new_raw=eip tracewalk

Или вы можете вывести список всех разрешений, установленных для данного исполняемого файла:

getcap tracewalk

Для справки, вы также можете удалить все разрешения из исполняемого файла с помощью:

setcap -r tracewalk

На этом этапе вы должны иметь возможность запускать исполняемый файл как непривилегированный пользователь, и он должен иметь возможность работать с необработанными сокетами, но не иметь никаких других привилегий, которыми обладает root-пользователь.

Итак, что означает этот странный суффикс =eip? Здесь потребуется толика понимания природы разрешений. Каждый процесс имеет три набора разрешений — эффективные, наследуемые и доступные (effective, inheritable и permitted):

  • Эффективные (Effective) разрешения — это те, которые определяют, что процесс может на самом деле делать. Например, он не может иметь дело с необработанными сокетами, если CAP_NET_RAW не находится в эффективном наборе.
  • Доступные (Permitted) разрешения — это те, которые разрешено иметь процессу, если он запрашивает их с помощью соответствующего вызова. Они не позволяют процессу фактически что-либо делать, если только он не был специально написан для запроса указанного разрешения. Это позволяет писать процессы для добавления особо важных разрешений в эффективный набор только на тот период, когда они действительно требуются.
  • Наследуемые (Inheritable) разрешения — это те, которые могут быть унаследованы в доступном наборе порожденного дочернего процесса. Во время операции fork() или clone() дочернему процессу всегда дается копия разрешений родительского процесса, поскольку в этот момент он все еще выполняет тот же исполняемый файл. Наследуемый набор используется, когда exec() (или аналог) вызывается для замены исполняемого файла другим. На этом этапе доступный набор процесса маскируется наследуемым набором для получения доступного набора, который будет использоваться для нового процесса.

Таким образом, утилита setcap позволяет нам добавлять разрешения этих трех наборов независимо для данного исполняемого файла. Обратите внимание, что значение групп интерпретируется немного по-разному для прав доступа к файлам:

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

При указании разрешений через setcap три буквы e, i и p относятся к эффективному, наследуемому и доступному множествам соответственно. Итак, более ранняя спецификация:

sudo setcap cap_net_raw=eip tracewalk

… указывает, что разрешение CAP_NET_RAW должно быть добавлено к доступным и наследуемым наборам и что также должен быть установлен эффективный бит. Это заменит любые ранее установленные разрешения в файле. Чтобы установить сразу несколько разрешений, используйте список через запятую:

sudo setcap cap_net_admin,cap_net_raw=eip tracewalk

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

Во-первых, файловые возможности не работают с симлинками — вы должны применить их к самому двоичному файлу (то есть к цели симлинка).

Во-вторых, они не работают с интерпретируемыми скриптами. Например, если у вас есть скрипт Python, которому вы хотите назначить разрешение, вы должны назначить его самому интерпретатору Python. Очевидно, что это потенциальная проблема безопасности, потому что тогда все скрипты, выполняемые с этим интерпретатором, будут иметь указанное разрешение, хотя это все же значительно лучше, чем сделать SUID. Наиболее распространенный обходной путь, по-видимому, заключается в написании отдельного исполняемого файла на C или аналоге, который может выполнять необходимые операции и вызывать его из скрипта. Это похоже на подход, используемый Wireshark, который использует двоичный файл /usr/bin/dumpcap для выполнения привилегированных операций:

$ getcap /usr/bin/dumpcap 
/usr/bin/dumpcap = cap_net_admin,cap_net_raw+eip

В-третьих, файловые разрешения отключаются, если вы используете переменную среды LD_LIBRARY_PATH по понятным причинам безопасности(1). То же самое относится и к LD_PRELOAD, насколько я знаю.

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

На этом все. Подробно о программе курса, можно будет узнать на вебинаре, который пройдет 24 января.

Источник: habr.com