Experiment 1 · Exercises: isolation
Exercises: isolating a run
The access rules of Experiment 1, §2.4, as textbook exercises. The code runs in your browser.
1. File permissions
(the permission check) [Kerrisk, TLPI, §15.4.3; Stevens & Rago, APUE, §4.5]
A file \(f\) has an owner, a group and a mode \(m\in\{0,\dots,7\}^3\) (bits r, w, x for u, g, o). A process \(p\) has a uid and a set of gids. Exactly one class applies:
$$\operatorname{cls}(p,f)=\begin{cases}u&\operatorname{uid}(p)=\operatorname{owner}(f),\\ g&\text{else, if }\operatorname{group}(f)\in\operatorname{gids}(p),\\ o&\text{else.}\end{cases}$$ $$\operatorname{may}(p,/d_1/\cdots/d_k/f,\ w)\iff \text{x}\in m_{\operatorname{cls}}(/),\,m_{\operatorname{cls}}(/d_1),\dots,m_{\operatorname{cls}}(/d_1/\cdots/d_k)\ \text{ and }\ w\in m_{\operatorname{cls}}(f);\qquad \operatorname{uid}(p)=0\Rightarrow\text{yes}.$$On a directory, r lists its names and x lets a path pass through it.
(this Mac today) predict
/Users/miltonlin is drwxr-x---, owner miltonlin, group staff; everything below it is 755 or 644. A new standard account exp1runner is in staff. Can it read ~miltonlin/Projects/Trees/README.md?
Yes. \(\operatorname{cls}=g\) at the home, whose group bits are r-x, so the path passes; README.md is 644. This is why §2.4.2 requires chmod 700 ~.
(the check, in code) code
Write cls and finish may. The tests include homes 711 and 744: decide before running whether either keeps exp1runner out.
2. Which hosts the proxy refuses
(domain match) [RFC 6265, §5.1.3; RFC 9110, §9.3.6]
A client behind the proxy opens each HTTPS connection with CONNECT host:port; the rest is encrypted. After lower-casing and removing the port and a final dot, a host \(h\) matches a domain \(d\) if
(the proxy's test) code
Write blocked for netproxy.py, with \(X\)'s host cwlin4916.github.io as the deny list.
(what the proxy cannot see) predict
A run fetches https://web.archive.org/web/2026/cwlin4916.github.io/Trees/. Can netproxy.py refuse it and still allow the rest of web.archive.org?
No. The path travels inside TLS, and the DNS lookup is for web.archive.org too. The URL part of \(X\) is enforced after the run, by the scan of each transcript's URLs and queries (§2.4.4).
3. Reads inside the run folder
(path containment) code [TLPI, §18.13; normpath]
The scan after a run (reads.txt) asks of each path read whether it lies in \(D_r\) = /Users/exp1runner/run. Write inside, lexically: no file is opened.
4. Firewall rules
(pf's rule order) [pf.conf(5); Hansteen, The Book of PF, ch. 3]
Rules \(\rho_1,\dots,\rho_n\) are read top to bottom; a packet \(q\) gets
$$\operatorname{act}(q)=\begin{cases}\operatorname{act}(\rho_i)&i=\min\{j:\rho_j\text{ matches }q,\ \rho_j\text{ quick}\}\text{ if that set is nonempty},\\ \operatorname{act}(\rho_i)&i=\max\{j:\rho_j\text{ matches }q\}\text{ else, if some rule matches},\\ \text{pass}&\text{else.}\end{cases}$$(the runner's anchor) code
Write decide. The tests run the anchor of §2.4.3 and two reorderings of it.
5. Independence as reads-from
(reads-from) [Bernstein, Hadzilacos & Goodman, ch. 2]
In a log of writes, reads and resets in time order, \(r\) reads \(p\) from \(w\) if \(w\) wrote \(p\) at \(t_w\lt t_r\) and nothing wrote \(p\) or reset in \((t_w,t_r)\). The condition \(\operatorname{reads}(r)\cap\operatorname{writes}(r')=\varnothing\) of §2.4.1 is about what was written, not about names:
$$r\ \text{independent}\iff\nexists\,(p,w):\ r\text{ reads }p\text{ from }w,\ \ w\notin\{r,\ \text{setup}\}.$$(the violations in a log) code
Every run writes tree.json in the same folder. Write violations; one test shows why comparing names would be wrong.
Your code is saved in this browser only. Python (Pyodide v0.26.4) loads from cdn.jsdelivr.net on the first run.