Lesson 09 / 09
Core Dump Analysis
Measuring the channel whose run cost is zero: a core dump brings back 3 of the 14 facts the strict bundle closes, the open surface becomes 13, and all four channels together bring back 8 facts, taking the return ratio to 0.5714; the dump's cost sits not in the run but in the sensitive data it carries.
Contents
Three channels have been measured, and all three ran during the run: system call tracing at 34 percent, in-kernel tracing at 6 percent, the sampling profile at 3 percent. The fourth channel sits outside this pattern. A core dump is written after a process has crashed; it charges the running process nothing, its run cost is 0 percent.
A channel with zero cost is expected to be harmless. The measurement says the opposite: the dump is among the top two in the number of facts it brings back — 3 — and among what it brings are user ID mapping and the capability set. This lesson resolves that contradiction — zero cost is not paid in the run, it is paid in retention — and closes the topic.
The Channel That Looks After the Run Ends
When a process ends on a fatal signal, the kernel can write the process’s memory image to a file. This file is not an event stream; it is a single snapshot, carrying the process’s final state: memory contents, privilege state, identity fields, traces of open resources.
Assumptions continue. The dump is written when the process ends and charges nothing during the run (OD22). The four facts the dump carries are the list in the code (OD23). Costs are percentages in the model, not a real measurement; the baseline run is 1000 time units (OD24). The dump is a single instant: for a fact that changes over the run, only its final value is visible (OD25). The dump file is persistent; the facts it carries stay visible as long as it can be read (OD26). All four channels can be on at once, and their run costs sum (OD27). The dump’s size and retention duration are not in the model (OD28), and this is the real cost that falls outside the measurement.
# example dump , has not been run $ cat /proc/sys/kernel/core_pattern <dump-path-template> $ ulimit -c <dump-size-limit> $ ls -l <dump-directory> -rw------- 1 <owner> <group> <size> <time> core.<process-name>.<no>
The block has not been run and its values are mock. That the file’s permission bits are narrow is not a coincidence; the reason is measured below.
# M03/K05 common definition -- this lesson builds all four channels. FACTS = [ ("other-process-list", "process"), ("own-process-number", "process"), ("ancestor-process-chain", "process"), ("root-filesystem-tree", "mount"), ("other-mounts", "mount"), ("shared-temp-directory", "mount"), ("host-interfaces", "network"), ("host-routing-table", "network"), ("listening-ports", "network"), ("user-id-mapping", "user"), ("file-ownership", "user"), ("hostname", "host"), ("cpu-share", "resource"), ("memory-limit", "resource"), ("memory-used", "resource"), ("cpu-count", "resource"), ("kernel-version", "kernel"), ("kernel-settings", "kernel"), ("system-load", "kernel"), ("clock", "kernel"), ("capability-set", "privilege"), ("file-permissions", "privilege"), ("security-label", "label"), ("policy-rules", "label"), ] MECHANISM = { "pid-namespace": {"axis": ["process"], "left_open": ["own-process-number"]}, "mount-namespace": {"axis": ["mount"], "left_open": ["root-filesystem-tree"]}, "network-namespace": {"axis": ["network"], "left_open": []}, "user-namespace": {"axis": ["user"], "left_open": ["file-ownership"]}, "uts-namespace": {"axis": ["host"], "left_open": []}, "control-group": {"axis": ["resource"], "left_open": ["cpu-count"]}, "capability-dropping": {"axis": ["privilege"], "left_open": ["file-permissions"]}, "mandatory-label": {"axis": ["label"], "left_open": ["security-label"]}, } STRICT_BUNDLE = ["pid-namespace", "mount-namespace", "network-namespace", "uts-namespace", "control-group", "capability-dropping", "user-namespace", "mandatory-label"] CHANNEL = { "system-call-tracing": ["root-filesystem-tree", "other-mounts", "file-ownership", "capability-set", "clock"], "sampling-profile": ["cpu-share", "cpu-count", "system-load"], "in-kernel-tracing": ["other-process-list", "ancestor-process-chain", "listening-ports", "kernel-settings", "system-load"], "core-dump": ["memory-used", "capability-set", "security-label", "user-id-mapping"], } # OD24: costs are MODEL percentages , not a real measurement CHANNEL_COST = {"system-call-tracing": 34, "sampling-profile": 3, "in-kernel-tracing": 6, "core-dump": 0} BASELINE_TIME = 1000 def visible(mechanisms, facts=FACTS): closed = set() for d in mechanisms: v = MECHANISM[d] for e in v["axis"]: closed |= {o for o, x in facts if x == e} closed -= set(v["left_open"]) return [o for o, _ in facts if o not in closed] def returned(mechanisms, channels, facts=FACTS): closed = {o for o, _ in facts} - set(visible(mechanisms, facts)) back = set() for k in channels: back |= set(CHANNEL[k]) & closed return sorted(back) def surface(mechanisms, channels=(), facts=FACTS): g = set(visible(mechanisms, facts)) back = set(returned(mechanisms, channels, facts)) return {"visible": len(g), "returned": len(back), "open_surface": len(g | back), "open_axes": len({e for o, e in facts if o in (g | back)})} g = set(visible(STRICT_BUNDLE)) closed = len(FACTS) - len(g) ys = surface(STRICT_BUNDLE, ["core-dump"]) print("facts:", len(FACTS), "| axes:", len({e for _, e in FACTS}), "| strict bundle: visible", len(g), "closed", closed) print() print("fact carried by dump axis status under strict bundle") for o in CHANNEL["core-dump"]: print(f" {o:26s}{dict(FACTS)[o]:11s}" f"{'already visible' if o in g else 'RETURNS'}") print() print("channel returned open surface open axes cost run") for k in CHANNEL: y = surface(STRICT_BUNDLE, [k]) b = CHANNEL_COST[k] print(f" {k:22s} {y['returned']:4d} {y['open_surface']:10d} {y['open_axes']:10d}" f" {b:5d} {BASELINE_TIME * (100 + b) // 100:5d}") h = surface(STRICT_BUNDLE, list(CHANNEL)) bh = sum(CHANNEL_COST.values()) print(f" {'ALL FOUR CHANNELS':22s} {h['returned']:4d} {h['open_surface']:10d}" f" {h['open_axes']:10d} {bh:5d} {BASELINE_TIME * (100 + bh) // 100:5d}") print() print("facts the strict bundle closes:", closed) print("returned by four channels :", h["returned"]) print("return ratio :", round(h["returned"] / closed, 4)) print("brought back by no channel :", sorted(set(o for o, _ in FACTS) - g - set(returned(STRICT_BUNDLE, list(CHANNEL))))) print() print("FACT SET SWEEP (all four channels)") changes = [o for o, _ in FACTS if surface(STRICT_BUNDLE, list(CHANNEL), [x for x in FACTS if x[0] != o])["open_surface"] != h["open_surface"]] grows = [e for e in sorted({e for _, e in FACTS}) if surface(STRICT_BUNDLE, list(CHANNEL), FACTS + [("new-fact", e)])["open_surface"] > h["open_surface"]] print(" removal: open surface", h["open_surface"], "| changes it", len(changes), "| does not", len(FACTS) - len(changes)) print(" addition: axis growing the surface", grows, "-> open surface", h["open_surface"] + 1)
facts: 24 | axes: 9 | strict bundle: visible 10 closed 14 fact carried by dump axis status under strict bundle memory-used resource RETURNS capability-set privilege RETURNS security-label label already visible user-id-mapping user RETURNS channel returned open surface open axes cost run system-call-tracing 2 12 7 34 1340 sampling-profile 1 11 7 3 1030 in-kernel-tracing 3 13 8 6 1060 core-dump 3 13 7 0 1000 ALL FOUR CHANNELS 8 18 8 43 1430 facts the strict bundle closes: 14 returned by four channels : 8 return ratio : 0.5714 brought back by no channel : ['host-interfaces', 'host-routing-table', 'hostname', 'memory-limit', 'policy-rules', 'shared-temp-directory'] FACT SET SWEEP (all four channels) removal: open surface 18 | changes it 18 | does not 6 addition: axis growing the surface ['kernel'] -> open surface 19
Oracle, Channel, Returning Fact
Three numbers sit side by side. Oracle: the process’s 24 facts, over nine axes. Channel: the core dump carries four facts. Returning fact and open surface: 3 of the four are facts the strict bundle closed and they return; the open surface climbs from 10 to 13, open axes stays at 7.
The returning trio is memory-used, capability-set, and user-id-mapping. All three are
facts three separate mechanisms close: the control group, capability dropping, and the user
namespace, respectively. A single file invalidates three separate isolation decisions at once.
The fourth fact, security-label, was already visible under the strict bundle; the mandatory
labeling mechanism deliberately leaves it open on its own axis.
Open axes staying at 7 confirms the distinction seen in the previous lesson: the dump reopens no closed axis, it thickens three open ones. Yet it takes the open surface to 13, and this, together with in-kernel tracing, is the largest single surface among the four channels. The channel with the lowest cost is one of the two channels that grow the surface the most.
Where Zero Cost Is Paid
The run cost is zero because the dump does not touch the running process. The cost is elsewhere, and it shows up in three forms.
The first is persistence (OD26). The other three channels give information for as long as they are on; visibility ends once they are turned off. The dump is a file: once written, it keeps showing the facts it carries until it is deleted. Tracing turned on for an hour produces an hour of visibility; a dump written once produces visibility for as long as it is retained.
The second is the file’s content. The dump carries the process’s memory image; whatever is in memory at that moment is in the dump too. This is a set far beyond the four facts counted in the measurement: processed data, session information, configuration values, and credentials can all sit in memory. A core dump carries sensitive data. This course does not write a procedure for extracting confidential data from a dump; what it measures is which fact the dump makes visible, not how that visibility gets abused.
The third is access. The path the dump is produced to and the file’s ownership determine who can read it. A dump written to a shared directory can be readable by processes outside the isolation bundle too.
The narrowing paths follow directly from this. Dump production can be turned off, or bound to a size limit through a per-process resource limit; dump production can also be separately blocked for privilege-escalating processes. The file is written with narrow permissions and to a directory only the privileged process can read, not to shared temp directories. Dumps are bound to a retention policy: they are deleted once diagnosis ends. Encryption at rest protects the file against backups and copies too. Together, the four make the real cost of a channel with zero run cost manageable.
The Four Channels’ Total
When all four channels are turned on together, the result is the course’s third claim. The strict bundle closed 14 of 24 facts; the four channels together bring back 8 of them. The return ratio is 0.5714: more than half of what isolation closes returns through observation. The open surface climbs from 10 to 18, open axes from 7 to 8. Total run cost is 43 percent and the run stretches to 1430; keeping all four on at once is a rare setup, but this line marks the setup’s limit.
The six facts that do not return are instructive too: host-interfaces, host-routing-table,
hostname, memory-limit, shared-temp-directory, and policy-rules. These are on no
channel’s list and stay closed. Isolation keeps working exactly where observation channels do
not look; what gets pierced is not the whole of isolation, it is the intersection the
channels cover.
The fact set sweep runs for the last time. On the removal side, the open surface changes with
18 of 24 facts, does not change with 6 — the ones that do not change are exactly the
six above. On the addition side, the surface again grows only on the kernel axis (18 to
19). The same result came up in all four lessons: an axis with no closer writes every fact
added to the list straight to the surface.
Summary
- The core dump carries four facts; 3 return (
memory-used,capability-set,user-id-mapping) and the open surface becomes 13. - Run cost is 0 percent; the cost sits in persistence, the file’s content, and its access. The dump carries sensitive data and its retention and access must be restricted.
- A single file invalidates three separate mechanisms’ decisions at once — the control group, capability dropping, the user namespace.
- All four channels together: returned 8, open surface 18, open axes 8, total cost 43 percent; return ratio 0.5714.
- Six facts return through no channel; isolation keeps working where the channels do not look.
- Narrowing: turning off dump production or binding it to a size limit, a narrow-permission unshared directory, a retention policy, and encryption at rest.
Course Wrap-Up
The course ran on a single rule: an isolation’s count is not the surface it closes, it is
the surface it leaves open; an isolation whose still-visible facts go unwritten counts as
unmeasured. The table below sets nine lessons side by side under the same measure. The
gozlem topic’s four rows are the numbers measured in this topic; the izolasyon topic’s five
rows are filled with those lessons’ own numbers.
| Lesson | Oracle | Isolation or channel | Open surface / returned |
|---|---|---|---|
| Namespaces | 24 facts / 9 axes | five namespaces | 15 visible; network and uts namespace are the only pair that closes its own axis fully |
| Control Groups | 24 facts / 9 axes | + control group | 12 visible; 3 facts close, cpu-count stays open |
| Capabilities | 24 facts / 9 axes | + capability dropping | 11 visible; only one of five capability sets closes, file permissions stay open |
| Mandatory Access Control | 8 of 36 access tuples required | + mandatory labeling | 10 visible (strict bundle); with no policy, 28 excess permissions, a rough policy 10, a narrow policy 1; in permissive mode, surface is 11 instead of 10 |
| Container Runtime | 24 facts / 9 axes | common 6 mechanisms / strict 8 mechanisms | 12 versus 10; two mechanisms narrow the surface by only 2 facts, open axes stays at 7 |
| System Call Tracing | 24 facts / 9 axes | channel: shows 5 facts, cost 34 percent | returned 2, open surface 12, open axes 7 |
| Performance Profiling | 24 facts / 9 axes | channel: shows 3 facts, cost 3 percent | returned 1, open surface 11, open axes 7 |
| In-Kernel Tracing | 24 facts / 9 axes | channel: shows 5 facts, cost 6 percent | returned 3, open surface 13, open axes 8 |
| Core Dump Analysis | 24 facts / 9 axes | channel: carries 4 facts, cost 0 percent | returned 3, open surface 13, open axes 7 |
The course’s two topics were opposites of one another, and the measurement wrote this down in numbers: isolation closed 14 facts, observation brought back 8 of them.
This lesson is also the end of the M03 curriculum. Five courses followed a single axis: the gap between the system’s real state and the evidence in the operator’s hand. Introduction to Linux measured reading names and permissions, Shell Programming turning a command into a tool, System Administration how many times the diagnosis drawn from output is wrong, Linux Network Administration and Troubleshooting narrowing a fault layer by layer, and Kernel Interfaces and Isolation the surface isolation leaves open.
Two debts were paid too. Namespaces and control groups had been referred to this course twice — in the System Administration course’s service manager lesson and in the Linux Network Administration course’s network configuration section. This course built both and measured both together with the surface they leave open: the pid namespace leaves its own process number open, the control group leaves the CPU count open, and observation channels bring back some of the facts both close.
Next comes the Computer Networks curriculum. In this course, the network passed through only as an axis: three facts closed, one channel reopening them. The network itself — the path a packet follows between two endpoints, the layers’ jobs, addressing, and protocols — is built there. The first course, How the Internet Works, begins by following the end-to-end journey of a request typed into an address bar.
To keep your progress and take notes, Log in
My notes
Log in to take notes.