time-namespace.md (10273B)
1 --- 2 title: "Time Namespace" 3 section: "Linux" 4 sectionSlug: "linux-hardening" 5 sourcePath: "src/linux-hardening/containers-namespaces/container-security/protections/namespaces/time-namespace.md" 6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/linux-hardening/containers-namespaces/container-security/protections/namespaces/time-namespace.md" 7 sha: "188de82beb54e70956b2952367a0af91d26758b8" 8 isIndex: false 9 modified: true 10 license: "CC-BY-NC-4.0" 11 --- 12 13 # Time Namespace 14 15 ## Overview 16 17 The time namespace virtualizes selected monotonic-style clocks instead of the host wall clock. In practice this means private offsets for **`CLOCK_MONOTONIC`** and **`CLOCK_BOOTTIME`**, plus the closely related **`CLOCK_MONOTONIC_COARSE`**, **`CLOCK_MONOTONIC_RAW`**, and **`CLOCK_BOOTTIME_ALARM`** views. It does **not** virtualize **`CLOCK_REALTIME`**, so `date` and certificate-expiry logic still observe the host wall clock unless some other mechanism interferes.<sup>[[1]](#references)</sup> 18 19 The main purpose is to let a process observe controlled elapsed-time offsets without changing the host's global time view. This is useful for checkpoint/restore workflows, deterministic testing, and advanced runtime behavior. It is not usually a headline isolation control in the same way as mount or user namespaces, but it still contributes to making the process environment more self-contained. 20 21 From an offensive point of view, this namespace is usually more relevant for **reconnaissance, timer skew, and runtime understanding** than for a direct breakout. Still, it matters because more container runtimes and checkpoint/restore workflows are now able to request it explicitly. 22 23 ## Lab 24 25 If the host kernel and userspace support it, you can inspect the namespace with: 26 27 ```bash 28 sudo unshare --time --fork bash 29 ls -l /proc/self/ns/time /proc/self/ns/time_for_children 30 python3 - <<'PY' 31 import time 32 print("realtime :", time.time()) 33 print("monotonic:", time.clock_gettime(time.CLOCK_MONOTONIC)) 34 print("boottime :", time.clock_gettime(time.CLOCK_BOOTTIME)) 35 PY 36 cat /proc/uptime 37 date 38 ``` 39 40 Support varies by kernel and tool versions, so this page is more about understanding the mechanism than expecting it to be visible in every lab environment. The important observation is that `date` should still reflect the host wall clock, while monotonic/boottime-based values are the ones that change when nonzero offsets are configured. 41 42 ### Creation Nuance 43 44 Time namespaces are slightly unusual compared to mount, PID, or network namespaces:<sup>[[1]](#references)</sup> 45 46 - `unshare(CLONE_NEWTIME)` creates a new time namespace for **future children**. 47 - The calling task stays in its current time namespace. 48 - `/proc/<pid>/ns/time_for_children` is therefore often more interesting than `/proc/<pid>/ns/time` when debugging runtime setup. 49 50 The write window is also special. Offsets in `/proc/<pid>/timens_offsets` must be written before the new time namespace is fully populated with running tasks; in practice runtimes do this during the narrow setup window between namespace creation and starting the final payload. Once a task is already running there, later writes fail with `EACCES`. This is why low-level runtimes handle time-namespace setup as an early bootstrap step instead of trying to patch offsets from inside an already-started container process.<sup>[[1]](#references)</sup> 51 52 ### Time Offsets 53 54 Linux time namespaces expose the per-namespace offsets through `/proc/<pid>/timens_offsets`. The format is a set of clock names or IDs plus second/nanosecond deltas relative to the initial time namespace.<sup>[[1]](#references)</sup> 55 56 In practice, the most reliable user-facing workflow is to let `unshare` write those offsets for you: 57 58 ```bash 59 sudo unshare -UrT --fork --mount-proc --monotonic 86400 --boottime 604800 bash 60 cat /proc/$$/timens_offsets 2>/dev/null 61 python3 - <<'PY' 62 import time 63 print("monotonic:", time.clock_gettime(time.CLOCK_MONOTONIC)) 64 print("boottime :", time.clock_gettime(time.CLOCK_BOOTTIME)) 65 print("uptime :", open("/proc/uptime").read().split()[0]) 66 PY 67 ``` 68 69 The important point is not the exact command syntax but the behavior: a container can observe a different uptime-like view without changing the host wall clock. 70 71 ### `unshare` Helper Flags 72 73 Recent `util-linux` versions provide convenience flags that write the offsets automatically during namespace creation: 74 75 ```bash 76 sudo unshare -T --fork --monotonic 86400 --boottime 604800 --mount-proc bash 77 ``` 78 79 These flags are mostly a usability improvement, but they also make it easier to recognize the feature in documentation, test harnesses, and runtime wrappers. 80 81 ## Runtime Usage 82 83 Time namespaces are newer and less universally exercised than mount or PID namespaces. OCI Runtime Specification v1.1 added explicit support for the `time` namespace and the `linux.timeOffsets` field, and modern runtimes can map that data into the kernel bootstrap flow. A minimal OCI fragment looks like: 84 85 ```json 86 { 87 "linux": { 88 "namespaces": [ 89 { "type": "time" } 90 ], 91 "timeOffsets": { 92 "monotonic": 86400, 93 "boottime": 600 94 } 95 } 96 } 97 ``` 98 99 This matters because it turns time namespacing from a niche kernel primitive into something that runtimes can request portably. It also explains why runtime internals need an explicit synchronization step: the offset must be written to `/proc/<pid>/timens_offsets` before the container payload fully enters the new namespace. 100 101 Checkpoint/restore stacks such as CRIU are one of the main real-world reasons this exists at all. Without time namespaces, restoring a paused workload would make monotonic and boot-time clocks jump by the amount of time the workload spent suspended.<sup>[[2]](#references)</sup> 102 103 ## Security Impact 104 105 There are fewer classic breakout stories centered on the time namespace than on other namespace types. The risk here is usually not that the time namespace directly enables escape, but that readers ignore it completely and therefore miss how advanced runtimes may be shaping process behavior. 106 107 In specialized environments, altered monotonic or boottime views can affect: 108 109 - timeout and retry behavior 110 - watchdogs and lease logic 111 - `timerfd`, `nanosleep`, and `clock_nanosleep` behavior 112 - checkpoint/restore forensics 113 - elapsed-time telemetry and uptime-based heuristics 114 115 So while this is rarely the first namespace you abuse, it can absolutely explain "impossible" timing behavior during an assessment. 116 117 ## Abuse 118 119 There is usually no direct breakout primitive here, but altered clock behavior can still be useful for understanding the execution environment, identifying advanced runtime features, and spotting timer-based logic that is measured against monotonic clocks instead of wall clock time: 120 121 ```bash 122 readlink /proc/self/ns/time 123 readlink /proc/self/ns/time_for_children 124 cat /proc/$$/timens_offsets 2>/dev/null 125 python3 - <<'PY' 126 import time 127 print("realtime :", time.time()) 128 print("monotonic:", time.clock_gettime(time.CLOCK_MONOTONIC)) 129 print("boottime :", time.clock_gettime(time.CLOCK_BOOTTIME)) 130 print("uptime :", open("/proc/uptime").read().split()[0]) 131 PY 132 ``` 133 134 If you are comparing two processes, differences here can help explain odd timing behavior, checkpoint/restore artifacts, or environment-specific logging mismatches. 135 136 Practical attacker-relevant angles: 137 138 - confuse backoff, sleep, or watchdog logic implemented with monotonic clocks 139 - explain why `/proc/uptime` and timer-driven behavior disagree with host-side wall-clock expectations 140 - recognize CRIU/checkpoint-restore workflows and other advanced runtime features 141 - spot environments where joining a target time namespace with `nsenter -T -t <pid> -- ...` may reproduce container-local timer behavior for debugging or post-exploitation 142 143 Impact: 144 145 - almost always reconnaissance or environment understanding 146 - useful for explaining logging, uptime, or checkpoint/restore anomalies 147 - useful for analyzing monotonic-time-based sleeps, retries, and timers 148 - not normally a direct container-escape mechanism by itself 149 150 The important abuse nuance is that time namespaces do not virtualize `CLOCK_REALTIME`, so they do not by themselves let an attacker falsify the host wall clock or directly break certificate-expiry checks system-wide. Their value is mostly in confusing monotonic-time-based logic, reproducing environment-specific bugs, or understanding advanced runtime behavior. 151 152 ## Checks 153 154 These checks are mostly about confirming whether the runtime is using a private time namespace at all and whether it actually set nonzero offsets. 155 156 ```bash 157 readlink /proc/self/ns/time # Current time namespace identifier 158 readlink /proc/self/ns/time_for_children # Time namespace inherited by children 159 cat /proc/$$/timens_offsets 2>/dev/null # Monotonic and boottime offsets when supported 160 lsns -t time 2>/dev/null # Host-side inventory when available 161 python3 - <<'PY' 162 import time 163 print("realtime :", time.time()) 164 print("monotonic:", time.clock_gettime(time.CLOCK_MONOTONIC)) 165 print("boottime :", time.clock_gettime(time.CLOCK_BOOTTIME)) 166 PY 167 ``` 168 169 What is interesting here: 170 171 - In many environments these values will not lead to an immediate security finding, but they do tell you whether a specialized runtime feature is in play. 172 - If `time_for_children` differs from `time`, the caller may have prepared a child-only time namespace that it has not entered itself. 173 - If `date` matches the host but monotonic/boottime-based values do not, you are probably looking at time namespacing rather than wall-clock tampering. 174 - If you are comparing two processes, differences here may explain confusing timing or checkpoint/restore behavior. 175 176 For most container breakouts, the time namespace is not the first control you will investigate. Still, a complete container-security section should mention it because it is part of the modern kernel model and occasionally matters in advanced runtime scenarios. 177 178 ## References 179 180 - [1] [Linux `time_namespaces(7)` manual page](https://man7.org/linux/man-pages/man7/time_namespaces.7.html) 181 - [2] [Time Namespaces: Per-Container Clock Offsets for CLOCK_MONOTONIC / CLOCK_BOOTTIME - Linux Kernel Internals](https://kernel-internals.org/time/time-namespaces/)