[Настройка Linux, Системное администрирование, Виртуализация] Почему в Docker не работает Strace (перевод)
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Когда я редактировала страницу о возможностях контейнеров для журнала «How Containers Work», мне потребовалось объяснить, почему в Docker не работает strace. Вот что случалось при запуске strace в Docker-контейнере на моем ноутбуке:
$ docker run -it ubuntu:18.04 /bin/bash
$ # ... install strace ...
root@e27f594da870:/# strace ls
strace: ptrace(PTRACE_TRACEME, ...): Operation not permitted
strace работает через системный вызов ptrace, поэтому без разрешения для ptrace ничего не заработает! Но это легко исправить, и на моем ноутбуке я все сделала вот так:
docker run --cap-add=SYS_PTRACE -it ubuntu:18.04 /bin/bash
Но мне было интересно не решить проблему, а разобраться, почему эта ситуация вообще возникает. Так почему же strace не работает, а --cap-add=SYS_PTRACE все исправляет?
Гипотеза 1: У процессов контейнеров нет собственной привилегии CAP_SYS_PTRACE
Так как проблема стабильно решается через --cap-add=SYS_PTRACE, мне всегда казалось, что у процессов контейнеров Docker по определению нет собственной привилегии CAP_SYS_PTRACE, но по двум причинам тут кое-что не сходится.
Причина 1: В виде эксперимента я, будучи залогиненной под обычным пользователем, без труда могла запустить strace к любому процессу, однако проверка наличия у моего текущего процесса привилегии CAP_SYS_PTRACE ничего не находила:
$ getpcaps $$
Capabilities for `11589': =
Причина 2: в man capabilities о привилегии CAP_SYS_PTRACE сказано следующее:
CAP_SYS_PTRACE
* Trace arbitrary processes using ptrace(2);
Вся суть CAP_SYS_PTRACE заключается в том, чтобы мы, по аналогии с root, могли перехватывать контроль над произвольным процессом любого пользователя. Для ptrace обычного процесса вашего пользователя такая привилегия не нужна.
Кроме того, я провела еще одну проверку: я запустила Docker контейнер через docker run --cap-add=SYS_PTRACE -it ubuntu:18.04 /bin/bash, затем отменила привилегию CAP_SYS_PTRACE — и strace продолжил корректно работать даже без привилегии. Почему?!
Гипотеза 2: Дело в пользовательском пространстве имен?
Моя следующая (и намного хуже обоснованная) гипотеза звучала в духе «хмм, возможно процесс находится в другом пользовательском пространстве имен и strace не работает… просто потому что?» Выглядит как набор не очень связных высказываний, но я все же попробовала посмотреть на проблему и с этой стороны.
Итак, находится ли процесс в другом пользовательском пространстве имен? Так он выглядит в контейнере:
root@e27f594da870:/# ls /proc/$$/ns/user -l
... /proc/1/ns/user -> 'user:[4026531837]'
А так он выглядит на хосте:
bork@kiwi:~$ ls /proc/$$/ns/user -l
... /proc/12177/ns/user -> 'user:[4026531837]'
root в контейнере это тот же самый пользователь, что и root на хосте, поскольку у них общий идентификатор в пользовательском пространстве имен (4026531837), так что с этой стороны не должно быть никаких мешающих работе strace причин. Как можно видеть, гипотеза оказалась так себе, но тогда я еще не осознавала, что пользователи в контейнере и на хосте совпадают, и этот поход казался мне интересным.
Гипотеза 3: Системный вызов ptrace блокируется правилом seccomp-bpf
Я уже знала, что для ограничения запуска большого числа системных вызовов процессорами контейнеров в Docker есть правило seccomp-bpf, и оказалось, что в его списке блокируемых по определению вызовов есть и ptrace! (На самом деле список вызовов это лист исключений и ptrace попросту в него не попадает, но результат от этого не меняется.)
Теперь понятно, почему в Docker контейнере не работает strace, ведь очевидно, что полностью заблокированный ptrace вызвать не получится.
Давайте проверим эту гипотезу и посмотрим, сможем ли мы воспользоваться strace в Docker контейнере, если отключим все правила seccomp:
$ docker run --security-opt seccomp=unconfined -it ubuntu:18.04 /bin/bash
$ strace ls
execve("/bin/ls", ["ls"], 0x7ffc69a65580 /* 8 vars */) = 0
... it works fine ...
Отлично! Все работает, и секрет раскрыт! Вот только…
Почему --cap-add=SYS_PTRACE решает проблему?
Мы все еще не объяснили почему --cap-add=SYS_PTRACE решает возникающую проблему с вызовами. Главная страница docker run следующим образом объясняет работу аргумента --cap-add:
--cap-add=[]
Add Linux capabilities
Все это не имеет никакого отношения к правилам seccomp! В чем же дело?
Давайте посмотрим на исходный код Docker.
Если уже и документация не помогает, все что нам остается это погрузиться в исходники.
В Go есть одна приятная особенность: благодаря вендорингу зависимостей в репозитории Go вы через grep можете пройтись по всему репозиторию и найти интересующий вас код. Так что я склонировала github.com/moby/moby и прошерстила его в поисках выражений вида rg CAP_SYS_PTRACE.
На мой взгляд, тут происходит вот что: в имплементации seccomp в контейнере, в разделе contrib/seccomp/seccomp_default.go полно кода, который через правило seccomp проверяет, есть ли у процесса с привилегиями разрешение на использование системных вызовов в соответствии с этой привилегией.
case "CAP_SYS_PTRACE":
s.Syscalls = append(s.Syscalls, specs.LinuxSyscall{
Names: []string{
"kcmp",
"process_vm_readv",
"process_vm_writev",
"ptrace",
},
Action: specs.ActAllow,
Args: []specs.LinuxSeccompArg{},
})
Там еще есть код, который в moby и для profiles/seccomp/seccomp.go, и для seccomp профиля по определению проводит похожие операции, так что, наверное, мы нашли наш ответ!
В Docker --cap-add способен на большее, чем сказано
В итоге, похоже, --cap-add делает не совсем то, что написано на главной странице, и скорее должен выглядеть как --cap-add-and-also-whitelist-some-extra-system-calls-if-required. И это похоже на правду: если у вас есть привилегия в духе CAP_SYS_PTRACE, которая разрешает вам пользоваться системным вызовом process_vm_readv, но этот вызов блокируется профилем seccomp, вам это мало чем поможет, так что разрешение на использование системных вызовов process_vm_readv и ptrace через CAP_SYS_PTRACE выглядит разумно.
Оказывается, strace работает в последних версиях Docker
Для версий ядра 4.8 и выше благодаря этому коммиту в Docker 19.03 наконец-то разрешены системные вызовы ptrace. Вот только на моем ноутбуке Docker все еще версии 18.09.7, и этот коммит, очевидно, отсутствует.
Вот и все!
Разбираться с этой проблемой оказалось интересно, и я думаю, что это хороший пример нетривиально взаимодействующей между собой подвижной «начинки» контейнеров.
Если вам понравился этот пост, вам может понравиться и мой журнал «How Containers Work», на его 24 страницах объясняются особенности ядра Linux по организации работы контейнеров. Там же вы можете ознакомиться с привилегиями и seccomp-bpf.
===========
Источник:
habr.com
===========
===========
Автор оригинала: Julia Evans
===========Похожие новости:
- [NoSQL, Open source] Создатель СУБД Redis уходит от сопровождения проекта
- [IT-инфраструктура, Open source, Виртуализация, Разработка под Linux, Сетевые технологии] Интеграция Open vSwitch с Р-виртуализацией
- [IT-компании, Системное администрирование, Софт] Microsoft закрыла две уязвимости в библиотеке Microsoft Windows Codecs для Windows 10 и Windows Server 2019
- [Системное администрирование, Софт] Microsoft выпустила собственный инструмент для восстановления удалённых файлов — Windows File Recovery
- [Open source, Настройка Linux, Процессоры] Линус Торвальдс о будущем Linux: «Сложно найти мейнтейнеров»
- [Информационная безопасность, Сетевые технологии, Системное администрирование] Check Point SandBlast Agent. Что нового?
- [Информационная безопасность, Монетизация мобильных приложений, Разработка мобильных приложений, Разработка под iOS] TikTok влезает в буфер обмена на iOS и попал под полный запрет в Индии
- [IT-инфраструктура, Виртуализация] Подводные камни при переходе на VDI: что тестировать заранее, чтобы не было мучительно больно
- [Системное администрирование, IT-инфраструктура, Серверное администрирование, Софт] Прячем RDP и быстро помогаем пользователям
- [IT-инфраструктура, IT-компании, Системное администрирование, Управление продуктом] О сколько нам открытий чудных готовят Parallels тут
Теги для поиска: #_nastrojka_linux (Настройка Linux), #_sistemnoe_administrirovanie (Системное администрирование), #_virtualizatsija (Виртуализация), #_itsumma, #_docker, #_strace, #_ptrace, #_protsessy (процессы), #_polzovateli (пользователи), #_pod_kapotom (под капотом), #_blog_kompanii_itsumma (
Блог компании ITSumma
), #_nastrojka_linux (
Настройка Linux
), #_sistemnoe_administrirovanie (
Системное администрирование
), #_virtualizatsija (
Виртуализация
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 03:19
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Когда я редактировала страницу о возможностях контейнеров для журнала «How Containers Work», мне потребовалось объяснить, почему в Docker не работает strace. Вот что случалось при запуске strace в Docker-контейнере на моем ноутбуке: $ docker run -it ubuntu:18.04 /bin/bash
$ # ... install strace ... root@e27f594da870:/# strace ls strace: ptrace(PTRACE_TRACEME, ...): Operation not permitted strace работает через системный вызов ptrace, поэтому без разрешения для ptrace ничего не заработает! Но это легко исправить, и на моем ноутбуке я все сделала вот так: docker run --cap-add=SYS_PTRACE -it ubuntu:18.04 /bin/bash
Но мне было интересно не решить проблему, а разобраться, почему эта ситуация вообще возникает. Так почему же strace не работает, а --cap-add=SYS_PTRACE все исправляет? Гипотеза 1: У процессов контейнеров нет собственной привилегии CAP_SYS_PTRACE Так как проблема стабильно решается через --cap-add=SYS_PTRACE, мне всегда казалось, что у процессов контейнеров Docker по определению нет собственной привилегии CAP_SYS_PTRACE, но по двум причинам тут кое-что не сходится. Причина 1: В виде эксперимента я, будучи залогиненной под обычным пользователем, без труда могла запустить strace к любому процессу, однако проверка наличия у моего текущего процесса привилегии CAP_SYS_PTRACE ничего не находила: $ getpcaps $$
Capabilities for `11589': = Причина 2: в man capabilities о привилегии CAP_SYS_PTRACE сказано следующее: CAP_SYS_PTRACE
* Trace arbitrary processes using ptrace(2); Вся суть CAP_SYS_PTRACE заключается в том, чтобы мы, по аналогии с root, могли перехватывать контроль над произвольным процессом любого пользователя. Для ptrace обычного процесса вашего пользователя такая привилегия не нужна. Кроме того, я провела еще одну проверку: я запустила Docker контейнер через docker run --cap-add=SYS_PTRACE -it ubuntu:18.04 /bin/bash, затем отменила привилегию CAP_SYS_PTRACE — и strace продолжил корректно работать даже без привилегии. Почему?! Гипотеза 2: Дело в пользовательском пространстве имен? Моя следующая (и намного хуже обоснованная) гипотеза звучала в духе «хмм, возможно процесс находится в другом пользовательском пространстве имен и strace не работает… просто потому что?» Выглядит как набор не очень связных высказываний, но я все же попробовала посмотреть на проблему и с этой стороны. Итак, находится ли процесс в другом пользовательском пространстве имен? Так он выглядит в контейнере: root@e27f594da870:/# ls /proc/$$/ns/user -l
... /proc/1/ns/user -> 'user:[4026531837]' А так он выглядит на хосте: bork@kiwi:~$ ls /proc/$$/ns/user -l
... /proc/12177/ns/user -> 'user:[4026531837]' root в контейнере это тот же самый пользователь, что и root на хосте, поскольку у них общий идентификатор в пользовательском пространстве имен (4026531837), так что с этой стороны не должно быть никаких мешающих работе strace причин. Как можно видеть, гипотеза оказалась так себе, но тогда я еще не осознавала, что пользователи в контейнере и на хосте совпадают, и этот поход казался мне интересным. Гипотеза 3: Системный вызов ptrace блокируется правилом seccomp-bpf Я уже знала, что для ограничения запуска большого числа системных вызовов процессорами контейнеров в Docker есть правило seccomp-bpf, и оказалось, что в его списке блокируемых по определению вызовов есть и ptrace! (На самом деле список вызовов это лист исключений и ptrace попросту в него не попадает, но результат от этого не меняется.) Теперь понятно, почему в Docker контейнере не работает strace, ведь очевидно, что полностью заблокированный ptrace вызвать не получится. Давайте проверим эту гипотезу и посмотрим, сможем ли мы воспользоваться strace в Docker контейнере, если отключим все правила seccomp: $ docker run --security-opt seccomp=unconfined -it ubuntu:18.04 /bin/bash
$ strace ls execve("/bin/ls", ["ls"], 0x7ffc69a65580 /* 8 vars */) = 0 ... it works fine ... Отлично! Все работает, и секрет раскрыт! Вот только… Почему --cap-add=SYS_PTRACE решает проблему? Мы все еще не объяснили почему --cap-add=SYS_PTRACE решает возникающую проблему с вызовами. Главная страница docker run следующим образом объясняет работу аргумента --cap-add: --cap-add=[]
Add Linux capabilities Все это не имеет никакого отношения к правилам seccomp! В чем же дело? Давайте посмотрим на исходный код Docker. Если уже и документация не помогает, все что нам остается это погрузиться в исходники. В Go есть одна приятная особенность: благодаря вендорингу зависимостей в репозитории Go вы через grep можете пройтись по всему репозиторию и найти интересующий вас код. Так что я склонировала github.com/moby/moby и прошерстила его в поисках выражений вида rg CAP_SYS_PTRACE. На мой взгляд, тут происходит вот что: в имплементации seccomp в контейнере, в разделе contrib/seccomp/seccomp_default.go полно кода, который через правило seccomp проверяет, есть ли у процесса с привилегиями разрешение на использование системных вызовов в соответствии с этой привилегией. case "CAP_SYS_PTRACE":
s.Syscalls = append(s.Syscalls, specs.LinuxSyscall{ Names: []string{ "kcmp", "process_vm_readv", "process_vm_writev", "ptrace", }, Action: specs.ActAllow, Args: []specs.LinuxSeccompArg{}, }) Там еще есть код, который в moby и для profiles/seccomp/seccomp.go, и для seccomp профиля по определению проводит похожие операции, так что, наверное, мы нашли наш ответ! В Docker --cap-add способен на большее, чем сказано В итоге, похоже, --cap-add делает не совсем то, что написано на главной странице, и скорее должен выглядеть как --cap-add-and-also-whitelist-some-extra-system-calls-if-required. И это похоже на правду: если у вас есть привилегия в духе CAP_SYS_PTRACE, которая разрешает вам пользоваться системным вызовом process_vm_readv, но этот вызов блокируется профилем seccomp, вам это мало чем поможет, так что разрешение на использование системных вызовов process_vm_readv и ptrace через CAP_SYS_PTRACE выглядит разумно. Оказывается, strace работает в последних версиях Docker Для версий ядра 4.8 и выше благодаря этому коммиту в Docker 19.03 наконец-то разрешены системные вызовы ptrace. Вот только на моем ноутбуке Docker все еще версии 18.09.7, и этот коммит, очевидно, отсутствует. Вот и все! Разбираться с этой проблемой оказалось интересно, и я думаю, что это хороший пример нетривиально взаимодействующей между собой подвижной «начинки» контейнеров. Если вам понравился этот пост, вам может понравиться и мой журнал «How Containers Work», на его 24 страницах объясняются особенности ядра Linux по организации работы контейнеров. Там же вы можете ознакомиться с привилегиями и seccomp-bpf. =========== Источник: habr.com =========== =========== Автор оригинала: Julia Evans ===========Похожие новости:
Блог компании ITSumma ), #_nastrojka_linux ( Настройка Linux ), #_sistemnoe_administrirovanie ( Системное администрирование ), #_virtualizatsija ( Виртуализация ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 03:19
Часовой пояс: UTC + 5