# Time Namespace {{#include ../../../../banners/hacktricks-training.md}} ## Basic Information Часовий простір у Linux дозволяє використовувати зсуви для системних монотонних і завантажувальних годинників для кожного простору. Він зазвичай використовується в контейнерах Linux для зміни дати/часу всередині контейнера та коригування годинників після відновлення з контрольної точки або знімка. ## Lab: ### Create different Namespaces #### CLI ```bash sudo unshare -T [--mount-proc] /bin/bash ``` Монтування нової інстанції файлової системи `/proc`, якщо ви використовуєте параметр `--mount-proc`, забезпечує, що новий простір монтування має **точний та ізольований вигляд інформації про процеси, специфічної для цього простору**.
Помилка: bash: fork: Не вдалося виділити пам'ять Коли `unshare` виконується без параметра `-f`, виникає помилка через те, як Linux обробляє нові PID (ідентифікатори процесів) простори. Основні деталі та рішення наведені нижче: 1. **Пояснення проблеми**: - Ядро Linux дозволяє процесу створювати нові простори за допомогою системного виклику `unshare`. Однак процес, який ініціює створення нового PID простору (який називається "процесом unshare"), не входить до нового простору; лише його дочірні процеси входять. - Виконання `%unshare -p /bin/bash%` запускає `/bin/bash` в тому ж процесі, що й `unshare`. Відповідно, `/bin/bash` та його дочірні процеси знаходяться в оригінальному PID просторі. - Перший дочірній процес `/bin/bash` у новому просторі стає PID 1. Коли цей процес завершується, це викликає очищення простору, якщо немає інших процесів, оскільки PID 1 має особливу роль усиновлення сирітських процесів. Ядро Linux тоді вимкне виділення PID у цьому просторі. 2. **Наслідок**: - Вихід PID 1 у новому просторі призводить до очищення прапора `PIDNS_HASH_ADDING`. Це призводить до того, що функція `alloc_pid` не може виділити новий PID при створенні нового процесу, що викликає помилку "Не вдалося виділити пам'ять". 3. **Рішення**: - Проблему можна вирішити, використовуючи параметр `-f` з `unshare`. Цей параметр змушує `unshare` створити новий процес після створення нового PID простору. - Виконання `%unshare -fp /bin/bash%` забезпечує, що команда `unshare` сама стає PID 1 у новому просторі. `/bin/bash` та його дочірні процеси тоді безпечно містяться в цьому новому просторі, запобігаючи передчасному виходу PID 1 та дозволяючи нормальне виділення PID. Забезпечивши, що `unshare` виконується з прапором `-f`, новий PID простір правильно підтримується, що дозволяє `/bin/bash` та його підпроцесам працювати без виникнення помилки виділення пам'яті.
#### Docker ```bash docker run -ti --name ubuntu1 -v /usr:/ubuntu1 ubuntu bash ``` ### Перевірте, в якому просторі імен знаходиться ваш процес ```bash ls -l /proc/self/ns/time lrwxrwxrwx 1 root root 0 Apr 4 21:16 /proc/self/ns/time -> 'time:[4026531834]' ``` ### Знайти всі простори часу ```bash sudo find /proc -maxdepth 3 -type l -name time -exec readlink {} \; 2>/dev/null | sort -u # Find the processes with an specific namespace sudo find /proc -maxdepth 3 -type l -name time -exec ls -l {} \; 2>/dev/null | grep ``` ### Увійти в простір часу ```bash nsenter -T TARGET_PID --pid /bin/bash ``` ## Маніпулювання часовими зсувами Починаючи з Linux 5.6, два годинники можуть бути віртуалізовані для кожного простору часу: * `CLOCK_MONOTONIC` * `CLOCK_BOOTTIME` Їхні делти на кожен простір часу відкриті (і можуть бути змінені) через файл `/proc//timens_offsets`: ``` $ sudo unshare -Tr --mount-proc bash # -T creates a new timens, -r drops capabilities $ cat /proc/$$/timens_offsets monotonic 0 boottime 0 ``` Файл містить два рядки – по одному для кожного годинника – з зсувом у **наносекундах**. Процеси, які мають **CAP_SYS_TIME** _в часовому просторі_, можуть змінювати значення: ``` # advance CLOCK_MONOTONIC by two days (172 800 s) echo "monotonic 172800000000000" > /proc/$$/timens_offsets # verify $ cat /proc/$$/uptime # first column uses CLOCK_MONOTONIC 172801.37 13.57 ``` Якщо вам потрібно, щоб настінний годинник (`CLOCK_REALTIME`) також змінювався, вам все ще потрібно покладатися на класичні механізми (`date`, `hwclock`, `chronyd`, …); він **не** є просторовим. ### `unshare(1)` допоміжні прапори (util-linux ≥ 2.38) ``` sudo unshare -T \ --monotonic="+24h" \ --boottime="+7d" \ --mount-proc \ bash ``` Довгі параметри автоматично записують обрані дельти в `timens_offsets` одразу після створення простору імен, що заощаджує ручне `echo`. --- ## Підтримка OCI та Runtime * **OCI Runtime Specification v1.1** (листопад 2023) додала спеціальний тип простору імен `time` та поле `linux.timeOffsets`, щоб контейнерні движки могли запитувати віртуалізацію часу у переносимий спосіб. * **runc >= 1.2.0** реалізує цю частину специфікації. Мінімальний фрагмент `config.json` виглядає так: ```json { "linux": { "namespaces": [ {"type": "time"} ], "timeOffsets": { "monotonic": 86400, "boottime": 600 } } } ``` Потім запустіть контейнер за допомогою `runc run `. > ЗАУВАЖТЕ: runc **1.2.6** (лютий 2025) виправив помилку "exec into container with private timens", яка могла призвести до зависання та потенційного DoS. Переконайтеся, що ви використовуєте версію ≥ 1.2.6 у виробництві. --- ## Розгляди безпеки 1. **Необхідна можливість** – Процес потребує **CAP_SYS_TIME** всередині свого простору імен користувача/часу, щоб змінити зсуви. Відмова від цієї можливості в контейнері (за замовчуванням у Docker та Kubernetes) запобігає маніпуляціям. 2. **Без змін годинника** – Оскільки `CLOCK_REALTIME` спільний з хостом, зловмисники не можуть підробити терміни дії сертифікатів, терміни дії JWT тощо лише за допомогою timens. 3. **Уникнення журналювання/виявлення** – Програмне забезпечення, яке покладається на `CLOCK_MONOTONIC` (наприклад, обмежувачі швидкості на основі часу безперервної роботи), може бути заплутаним, якщо користувач простору імен регулює зсув. Віддавайте перевагу `CLOCK_REALTIME` для часових міток, що мають значення для безпеки. 4. **Поверхня атаки ядра** – Навіть якщо `CAP_SYS_TIME` видалено, код ядра залишається доступним; підтримуйте хост в актуальному стані. Linux 5.6 → 5.12 отримав кілька виправлень помилок timens (NULL-deref, проблеми з підписом). ### Контрольний список посилення безпеки * Відмовтеся від `CAP_SYS_TIME` у вашому профілі за замовчуванням контейнерного виконання. * Підтримуйте виконання в актуальному стані (runc ≥ 1.2.6, crun ≥ 1.12). * Закріпіть util-linux ≥ 2.38, якщо ви покладаєтеся на допоміжні програми `--monotonic/--boottime`. * Аудит програмного забезпечення в контейнері, яке читає **uptime** або **CLOCK_MONOTONIC** для логіки, критично важливої для безпеки. ## Посилання * man7.org – Сторінка посібника по просторах імен часу: * Блог OCI – "OCI v1.1: нові простори імен часу та RDT" (15 листопада 2023): {{#include ../../../../banners/hacktricks-training.md}}