Update on Overleaf.
182
diagrams/openbsd-syslogd-privsep.tex
Normal file
@ -0,0 +1,182 @@
|
||||
\documentclass[12pt,crop,tikz]{standalone}
|
||||
|
||||
\providecommand{\rootdir}{..}
|
||||
\usetikzlibrary{backgrounds}
|
||||
\usetikzlibrary{positioning}
|
||||
\usetikzlibrary{calc}
|
||||
\usetikzlibrary{decorations.pathreplacing}
|
||||
|
||||
\tikzstyle{arrow} = [thick,->,>=stealth]
|
||||
|
||||
% The Tableau20 colours
|
||||
\definecolor{TabLightOrange}{RGB}{255,187,120}
|
||||
\definecolor{TabOrange}{RGB}{255,127,14}
|
||||
\definecolor{TabLightBlue}{RGB}{174,199,232}
|
||||
\definecolor{TabBlue}{RGB}{31,119,180}
|
||||
\definecolor{TabGreen}{RGB}{44,160,44}
|
||||
\definecolor{TabLightGreen}{RGB}{152,223,138}
|
||||
\definecolor{TabSalmon}{RGB}{255,152,150}
|
||||
\definecolor{TabRed}{RGB}{214,39,40}
|
||||
\definecolor{TabPurple}{RGB}{148,103,189}
|
||||
\definecolor{TabLightPurple}{RGB}{197,176,213}
|
||||
\definecolor{TabLightPink}{RGB}{247,182,210}
|
||||
\definecolor{TabPink}{RGB}{227,119,194}
|
||||
\definecolor{TabLightBrown}{RGB}{196,156,148}
|
||||
\definecolor{TabBrown}{RGB}{140,86,75}
|
||||
\definecolor{TabGray}{RGB}{127,127,127}
|
||||
\definecolor{TabOlive}{RGB}{188,189,34}
|
||||
\definecolor{TabLightOlive}{RGB}{219,219,141}
|
||||
\definecolor{TabLightGray}{RGB}{199,199,199}
|
||||
\definecolor{TabLightCyan}{RGB}{158,218,229}
|
||||
\definecolor{TabCyan}{RGB}{23,190,207}
|
||||
|
||||
\begin{document}
|
||||
|
||||
\def\titlepad{0.1}
|
||||
\def\boxspacing{40mm}
|
||||
|
||||
\def\layer{0.3}
|
||||
|
||||
\def\inner{0.3}
|
||||
\def\innerspace{0.2}
|
||||
|
||||
\def\layerwidth{5cm}
|
||||
\def\halflayerwidth{2.35cm}
|
||||
\def\layerheight{0.8cm}
|
||||
\def\innerwidth{4.4cm}
|
||||
\def\halfinnerwidth{2.1cm}
|
||||
|
||||
\begin{tikzpicture}
|
||||
[ every node/.style={font=\small}
|
||||
, layer/.style= {rectangle, draw=black!50, thick, minimum width=\layerwidth , minimum height=\layerheight}
|
||||
, halflayer/.style={rectangle, draw=black!50, thick, minimum width=\halflayerwidth, minimum height=\layerheight}
|
||||
, inner/.style= {rectangle, draw=black!50, thick, minimum width=\innerwidth , minimum height=\layerheight}
|
||||
, halfinner/.style={rectangle, draw=black!50, thick, minimum width=\halfinnerwidth, minimum height=\layerheight}
|
||||
, red/.style={fill=TabPurple!40}
|
||||
, orange/.style={fill=TabBlue!40}
|
||||
, yellow/.style={fill=TabCyan!40}
|
||||
, green/.style={fill=TabLightGreen!60}
|
||||
, node distance = 0cm
|
||||
, arrow={->,>=stealth}
|
||||
]
|
||||
|
||||
%-----------------------------------------------------------------------------
|
||||
% conventional syslogd
|
||||
%-----------------------------------------------------------------------------
|
||||
|
||||
\begin{scope}[local bounding box=syslogd]
|
||||
\node[layer] (syslogd-root) {Root privilege};
|
||||
|
||||
% hack to get the spacing right
|
||||
\coordinate (std-spaced_app1) at ($ (syslogd-root.south)+(0,-\inner) $);
|
||||
|
||||
\node[layer, orange, below = 2mm of syslogd-root] (syslogd-app) {syslogd.c};
|
||||
|
||||
\node[layer, fill=white, below = 2*\layer of syslogd-app] (syslogd-untrusted) {Untrusted user data};
|
||||
|
||||
% Lines down the left
|
||||
\coordinate (std-lline) at ($ (syslogd-app) + (-1.15,0) $);
|
||||
\draw[->] (std-lline |- 0, 0 |- syslogd-root.south) -- (std-lline |- 0, 0 |- syslogd-app.north);
|
||||
|
||||
% Lines down the right
|
||||
\coordinate (std-rline) at ($ (syslogd-app) + (1.15,0) $);
|
||||
\draw[->] (std-rline |- 0, 0 |- syslogd-app.north) -- (std-rline |- 0, 0 |- syslogd-root.south);
|
||||
|
||||
\end{scope}
|
||||
|
||||
\begin{scope}[local bounding box=syslogd-kernel]
|
||||
\fill[gray!15] ($ (syslogd-untrusted.north west) + (-\layer,\layer) $) rectangle ($ (syslogd-untrusted.south east) + (\layer, -\layer) $);
|
||||
\end{scope}
|
||||
\draw[-, gray, dashed] (syslogd-kernel.north west) -- (syslogd-kernel.north east);
|
||||
|
||||
\node[layer, fill=white, below = 2*\layer of syslogd-app] (syslogd-untrusted) {Untrusted user data};
|
||||
\draw[->] (std-lline |- 0, 0 |- syslogd-app.south) -- (std-lline |- 0, 0 |- syslogd-untrusted.north);
|
||||
\draw[<-] (std-rline |- 0, 0 |- syslogd-app.south) -- (std-rline |- 0, 0 |- syslogd-untrusted.north);
|
||||
|
||||
\coordinate (syslogd-nw) at ($ (syslogd.north west) + (-\inner, \inner + \titlepad) $);
|
||||
\coordinate (syslogd-ne) at ($ (syslogd.north east) + ( \inner, \inner + \titlepad) $);
|
||||
\coordinate (syslogd-sw) at ($ (syslogd.south west) + (-\inner,-\inner) $);
|
||||
\coordinate (syslogd-se) at ($ (syslogd.south east) + ( \inner,-\inner) $);
|
||||
|
||||
\draw[draw, thick] (syslogd-nw) rectangle (syslogd-se);
|
||||
\node[rectangle, fill=white] at ($(syslogd-nw)!0.5!(syslogd-ne)$) (syslogd_label) {\normalsize\textbf{Conventional syslogd}};
|
||||
|
||||
%-----------------------------------------------------------------------------
|
||||
% privsep syslogd
|
||||
% -----------------------------------------------------------------------------
|
||||
|
||||
\begin{scope}[local bounding box=client]
|
||||
% \coordinate[right=5cm of syslogd-] (client_center)
|
||||
|
||||
\node[layer, below = 3cm of syslogd] (privsep-syslogd-root) {Root privilege};
|
||||
|
||||
% hack to get the spacing right
|
||||
\coordinate (spaced_app1) at ($ (privsep-syslogd-root.south)+(0,-\inner) $);
|
||||
|
||||
\begin{scope}[local bounding box=privsep-syslogd-app]
|
||||
\node[inner, red, below = \layer of spaced_app1, yshift=-0.2cm] (rpc1) {privsep.c};
|
||||
|
||||
\node[inner, orange, below = 2mm of rpc1] (rpc2) {syslogd.c};
|
||||
\end{scope}
|
||||
|
||||
\coordinate (rpc1-nw) at ($ (privsep-syslogd-app.north west) + (-0.3, 0.3 + \titlepad) $);
|
||||
\coordinate (rpc1-ne) at ($ (privsep-syslogd-app.north east) + ( 0.3, 0.3 + \titlepad) $);
|
||||
\coordinate (rpc1-sw) at ($ (privsep-syslogd-app.south west) + (-0.3,-0.3) $);
|
||||
\coordinate (rpc1-se) at ($ (privsep-syslogd-app.south east) + ( 0.3,-0.3) $);
|
||||
|
||||
\draw[draw,thick,dotted] (rpc1-nw) rectangle (rpc1-se);
|
||||
|
||||
\coordinate (rpc-bottom) at ($(privsep-syslogd-app.south west)!0.5!(privsep-syslogd-app.south east) + (0, -0.3)$);
|
||||
|
||||
\node[layer, fill=white, below = 3*\layer of privsep-syslogd-app] (privsep-syslogd-untrusted) {Untrusted user data};
|
||||
|
||||
% Lines down the left
|
||||
\coordinate (lline) at ($ (privsep-syslogd-app) + (-1.15,0) $);
|
||||
\draw[->] (lline |- 0, 0 |- privsep-syslogd-root.south) -- (lline |- 0, 0 |- rpc1.north);
|
||||
\draw[->] (lline |- 0, 0 |- rpc1.south) -- (lline |- 0, 0 |- rpc2.north);
|
||||
|
||||
% Lines down the right
|
||||
\coordinate (rline) at ($ (privsep-syslogd-app) + (1.15,0) $);
|
||||
\draw[->] (rline |- 0, 0 |- rpc1.north) -- (rline |- 0, 0 |- privsep-syslogd-root.south);
|
||||
\draw[->] (rline |- 0, 0 |- rpc2.north) -- (rline |- 0, 0 |- rpc1.south);
|
||||
\end{scope}
|
||||
|
||||
\begin{scope}[on background layer, local bounding box=client-kernel]
|
||||
\fill[gray!15] ($ (privsep-syslogd-untrusted.north west) + (-\layer,\layer) $) rectangle ($ (privsep-syslogd-untrusted.south east) + (\layer, -\layer) $);
|
||||
\end{scope}
|
||||
|
||||
\draw[-, gray, dashed] (client-kernel.north west) -- (client-kernel.north east);
|
||||
|
||||
\coordinate (client-nw) at ($ (client.north west) + (-\inner, \inner + \titlepad) $);
|
||||
\coordinate (client-ne) at ($ (client.north east) + ( \inner, \inner + \titlepad) $);
|
||||
\coordinate (client-sw) at ($ (client.south west) + (-\inner,-\inner) $);
|
||||
\coordinate (client-se) at ($ (client.south east) + ( \inner,-\inner) $);
|
||||
|
||||
\draw[draw, thick] (client-nw) rectangle (client-se);
|
||||
\node[rectangle, fill=white] at ($(client-nw)!0.5!(client-ne)$) (client_label) {\normalsize\textbf{privsep syslogd}};
|
||||
|
||||
\draw[->] (lline |- 0, 0 |- privsep-syslogd-app.south) -- (lline |- 0, 0 |- privsep-syslogd-untrusted.north);
|
||||
\draw[<-] (rline |- 0, 0 |- privsep-syslogd-app.south) -- (rline |- 0, 0 |- privsep-syslogd-untrusted.north);
|
||||
|
||||
% \begin{scope}[local bounding box=cloud,shift={($(cloud_center) + (0, -0.05)$)}, rotate=0, scale=0.5]
|
||||
% \draw[fill=white,thick] (-1.6,-0.7) .. controls (-2.3,-1.1)
|
||||
% and (-2.7,0.3) .. (-1.7,0.3) .. controls (-1.6,0.7)
|
||||
% and (-1.2,0.9) .. (-0.8,0.7) .. controls (-0.5,1.5)
|
||||
% and (0.6,1.3) .. (0.7,0.5) .. controls (1.5,0.4)
|
||||
% and (1.2,-1) .. (0.4,-0.6) .. controls (0.2,-1)
|
||||
% and (-0.2,-1) .. (-0.5,-0.7) .. controls (-0.9,-1)
|
||||
% and (-1.3,-1) .. cycle;
|
||||
% \end{scope}
|
||||
|
||||
\coordinate (yheight) at ($ (syslogd-root.east) + (0, -1) $);
|
||||
\coordinate (trans-arrow-l) at (syslogd-kernel.east |- 0, 0 |- yheight);
|
||||
\coordinate (trans-arrow-r) at (client-kernel.west |- 0, 0 |- yheight);
|
||||
%\draw[very thick, ->] ($(trans-arrow-l) + (0.5, 0)$) -- node[above, text width = 4cm, align = center, yshift=3mm]
|
||||
|
||||
%\draw[very thick, ->] (syslogd-kernel) -- ($ (client.north) + (0, 2*\inner) $)
|
||||
|
||||
\draw[very thick, ->] (syslogd-kernel.south) -- node[right, text width = 2.7cm, align = center, yshift=0.5mm]
|
||||
{\normalsize\emph{Separate risk \\[1mm] from reward}} ($ (client.north) + (0, 2*\inner) $);
|
||||
|
||||
\end{tikzpicture}
|
||||
\end{document}
|
@ -8,20 +8,6 @@
|
||||
|
||||
\tikzstyle{arrow} = [thick,->,>=stealth]
|
||||
|
||||
\def\titlepad{0.1}
|
||||
\def\boxspacing{40mm}
|
||||
|
||||
\def\layer{0.3}
|
||||
|
||||
\def\inner{0.3}
|
||||
\def\innerspace{0.2}
|
||||
|
||||
\def\layerwidth{5cm}
|
||||
\def\halflayerwidth{2.35cm}
|
||||
\def\layerheight{0.8cm}
|
||||
\def\innerwidth{4.4cm}
|
||||
\def\halfinnerwidth{2.1cm}
|
||||
|
||||
% The Tableau20 colours
|
||||
\definecolor{TabLightOrange}{RGB}{255,187,120}
|
||||
\definecolor{TabOrange}{RGB}{255,127,14}
|
||||
@ -45,12 +31,29 @@
|
||||
\definecolor{TabCyan}{RGB}{23,190,207}
|
||||
|
||||
\begin{document}
|
||||
|
||||
\def\titlepad{0.1}
|
||||
\def\boxspacing{40mm}
|
||||
|
||||
\def\layer{0.3}
|
||||
|
||||
\def\inner{0.3}
|
||||
\def\innerspace{0.2}
|
||||
|
||||
\def\layerwidth{15cm}
|
||||
\def\halflayerwidth{2.35cm}
|
||||
\def\thirdlayerwidth{4.85cm}
|
||||
\def\layerheight{0.8cm}
|
||||
\def\innerwidth{4.4cm}
|
||||
\def\halfinnerwidth{2.1cm}
|
||||
|
||||
\begin{tikzpicture}
|
||||
[ every node/.style={font=\small}
|
||||
, layer/.style= {rectangle, draw=black!50, thick, minimum width=\layerwidth , minimum height=\layerheight}
|
||||
, halflayer/.style={rectangle, draw=black!50, thick, minimum width=\halflayerwidth, minimum height=\layerheight}
|
||||
, inner/.style= {rectangle, draw=black!50, thick, minimum width=\innerwidth , minimum height=\layerheight}
|
||||
, halfinner/.style={rectangle, draw=black!50, thick, minimum width=\halfinnerwidth, minimum height=\layerheight}
|
||||
, dashed/.style= {rectangle, draw=black!25, dotted, thick, minimum width=\innerwidth, minimum height=\layerheight}
|
||||
, red/.style={fill=TabPurple!40}
|
||||
, orange/.style={fill=TabBlue!40}
|
||||
, yellow/.style={fill=TabCyan!40}
|
||||
@ -59,156 +62,58 @@
|
||||
, arrow={->,>=stealth}
|
||||
]
|
||||
|
||||
%-----------------------------------------------------------------------------
|
||||
% Conventional client-side stack
|
||||
%-----------------------------------------------------------------------------
|
||||
|
||||
\begin{scope}[local bounding box=std-client]
|
||||
\node[layer] (std-client-app) {Application};
|
||||
\node[layer] (ambient-authority) {Ambient Authority};
|
||||
\node[layer, orange, below = 2mm of ambient-authority] (void-orchestrator) {Void Orchestrator};
|
||||
|
||||
\draw[->] (ambient-authority.south) -- (void-orchestrator.north);
|
||||
|
||||
% hack to get the spacing right
|
||||
\coordinate (std-spaced_app1) at ($ (std-client-app.south)+(0,-\inner) $);
|
||||
\coordinate (std-spaced_app1) at ($ (void-orchestrator.south)+(0,-\inner) $);
|
||||
|
||||
\begin{scope}[local bounding box=std-rpc-client]
|
||||
\node[inner, red, below = \layer of std-spaced_app1, yshift=-0.2cm] (std-rpc1) {Interface};
|
||||
\node[inner, orange, below = 2mm of std-rpc1] (std-rpc2) {Protocol};
|
||||
|
||||
\node[halfinner, yellow, below = 2mm of std-rpc2, xshift=-1.15cm] (std-rpc3a) {Serialiser};
|
||||
\node[halfinner, yellow, below = 2mm of std-rpc2, xshift= 1.15cm] (std-rpc3b) {Deserialiser};
|
||||
\begin{scope}[local bounding box=spawners]
|
||||
\node[inner, red, below = \layer of std-spaced_app1, yshift=-0.2cm] (tls-handler-spawner) {TLS Handler Spawner};
|
||||
\node[dashed, left = 5.5mm of tls-handler-spawner] (connection-listener-spawner) {};
|
||||
\node[inner, red, right = 5.5mm of tls-handler-spawner] (http-handler-spawner) {HTTP Handler Spawner};
|
||||
\end{scope}
|
||||
|
||||
\coordinate (std-rpc1-nw) at ($ (std-rpc-client.north west) + (-0.3, 0.3 + \titlepad) $);
|
||||
\coordinate (std-rpc1-ne) at ($ (std-rpc-client.north east) + ( 0.3, 0.3 + \titlepad) $);
|
||||
\coordinate (std-rpc1-sw) at ($ (std-rpc-client.south west) + (-0.3,-0.3) $);
|
||||
\coordinate (std-rpc1-se) at ($ (std-rpc-client.south east) + ( 0.3,-0.3) $);
|
||||
\node[inner, green, below = 2*\layer of connection-listener-spawner] (connection-listener) {Connection Listener};
|
||||
\node[inner, green, below = 2*\layer of tls-handler-spawner] (tls-handler) {TLS Handler};
|
||||
\node[inner, green, below = 2*\layer of http-handler-spawner] (http-handler) {HTTP Handler};
|
||||
|
||||
\draw[draw,thick,dotted] (std-rpc1-nw) rectangle (std-rpc1-se);
|
||||
\node[rectangle,fill=white] at ($(std-rpc1-nw)!0.5!(std-rpc1-ne)$) (std-rpc1_label) {\textit{SunRPC}};
|
||||
|
||||
\coordinate (std-rpc-bottom) at ($(std-rpc-client.south west)!0.5!(std-rpc-client.south east) + (0, -0.3)$);
|
||||
\node[layer, fill=white, below = 2*\layer of std-rpc-bottom] (std-Db) {Network stack};
|
||||
\coordinate (spawners-nw) at ($ (spawners.north west) + (-0.3, 0.3 + \titlepad) $);
|
||||
\coordinate (spawners-ne) at ($ (spawners.north east) + ( 0.3, 0.3 + \titlepad) $);
|
||||
\coordinate (spawners-sw) at ($ (spawners.south west) + (-0.3,-0.3) $);
|
||||
\coordinate (spawners-se) at ($ (spawners.south east) + ( 0.3,-0.3) $);
|
||||
|
||||
% Lines down the left
|
||||
\coordinate (std-lline) at (std-rpc3a);
|
||||
\draw[->] (std-lline |- 0, 0 |- std-client-app.south) -- (std-lline |- 0, 0 |- std-rpc1.north);
|
||||
\draw[->] (std-lline |- 0, 0 |- std-rpc1.south) -- (std-lline |- 0, 0 |- std-rpc2.north);
|
||||
\draw[->] (std-lline |- 0, 0 |- std-rpc2.south) -- (std-lline |- 0, 0 |- std-rpc3a.north);
|
||||
\draw[draw,thick,dotted] (spawners-nw) rectangle (spawners-se);
|
||||
\node[rectangle,fill=white] at ($(spawners-nw)!0.5!(spawners-ne)$) (spawners_label) {\textit{Spawners}};
|
||||
|
||||
% Lines down the right
|
||||
\coordinate (std-rline) at (std-rpc3b);
|
||||
\draw[->] (std-rline |- 0, 0 |- std-rpc1.north) -- (std-rline |- 0, 0 |- std-client-app.south);
|
||||
\draw[->] (std-rline |- 0, 0 |- std-rpc2.north) -- (std-rline |- 0, 0 |- std-rpc1.south);
|
||||
\draw[->] (std-rline |- 0, 0 |- std-rpc3a.north) -- (std-rline |- 0, 0 |- std-rpc2.south);
|
||||
% Left line locations (to avoid spawner header)
|
||||
\coordinate (left-lline) at ($ (connection-listener-spawner) + (-1.15,0) $);
|
||||
\coordinate (mid-lline) at ($ (tls-handler-spawner) + (-1.15,0) $);
|
||||
\coordinate (right-lline) at ($ (http-handler-spawner) + (-1.15,0) $);
|
||||
|
||||
% Lines for the left set
|
||||
\draw[->] (left-lline |- 0, 0 |- void-orchestrator.south) -- (left-lline |- 0, 0 |- connection-listener.north);
|
||||
|
||||
% Lines for the center set
|
||||
\draw[->] (mid-lline |- 0, 0 |- void-orchestrator.south) -- (mid-lline |- 0, 0 |- tls-handler-spawner.north);
|
||||
\draw[->] (mid-lline |- 0, 0 |- tls-handler-spawner.south) -- (mid-lline |- 0, 0 |- tls-handler.north);
|
||||
|
||||
% Lines for the right set
|
||||
\draw[->] (right-lline |- 0, 0 |- void-orchestrator.south) -- (right-lline |- 0, 0 |- http-handler-spawner.north);
|
||||
\draw[->] (right-lline |- 0, 0 |- http-handler-spawner.south) -- (right-lline |- 0, 0 |- http-handler.north);
|
||||
|
||||
\end{scope}
|
||||
|
||||
\begin{scope}[local bounding box=std-client-kernel]
|
||||
\fill[gray!15] ($ (std-Db.north west) + (-\layer,\layer) $) rectangle ($ (std-Db.south east) + (\layer, -\layer) $);
|
||||
\end{scope}
|
||||
\draw[-, gray, dashed] (std-client-kernel.north west) -- (std-client-kernel.north east);
|
||||
|
||||
\node[layer, fill=white, below = 2*\layer of std-rpc-bottom] (std-Db) {Network stack};
|
||||
\draw[->] (std-lline |- 0, 0 |- std-rpc3a.south) -- (std-lline |- 0, 0 |- std-Db.north);
|
||||
\draw[<-] (std-rline |- 0, 0 |- std-rpc3b.south) -- (std-rline |- 0, 0 |- std-Db.north);
|
||||
|
||||
\coordinate (std-client-nw) at ($ (std-client.north west) + (-\inner, \inner + \titlepad) $);
|
||||
\coordinate (std-client-ne) at ($ (std-client.north east) + ( \inner, \inner + \titlepad) $);
|
||||
\coordinate (std-client-sw) at ($ (std-client.south west) + (-\inner,-\inner) $);
|
||||
\coordinate (std-client-se) at ($ (std-client.south east) + ( \inner,-\inner) $);
|
||||
|
||||
\draw[draw, thick] (std-client-nw) rectangle (std-client-se);
|
||||
\node[rectangle, fill=white] at ($(std-client-nw)!0.5!(std-client-ne)$) (std-client_label) {\normalsize\textbf{Conventional RPC client}};
|
||||
|
||||
%-----------------------------------------------------------------------------
|
||||
% CausalRPC client-side stack
|
||||
% -----------------------------------------------------------------------------
|
||||
|
||||
\begin{scope}[local bounding box=client]
|
||||
% \coordinate[right=5cm of std-client-] (client_center)
|
||||
|
||||
\node[layer, right = 5cm of std-client-app] (client-app) {Application};
|
||||
|
||||
% hack to get the spacing right
|
||||
\coordinate (spaced_app1) at ($ (client-app.south)+(0,-\inner) $);
|
||||
|
||||
\begin{scope}[local bounding box=rpc-client]
|
||||
\node[inner, red, below = \layer of spaced_app1, yshift=-0.2cm] (rpc1) {Interface};
|
||||
\node[inner, orange, below = 2mm of rpc1] (rpc2) {Protocol};
|
||||
|
||||
\node[halfinner, yellow, below = 2mm of rpc2, xshift=-1.15cm] (rpc3a) {Pickler};
|
||||
\node[halfinner, yellow, below = 2mm of rpc2, xshift= 1.15cm] (rpc3b) {Unpickler};
|
||||
\end{scope}
|
||||
|
||||
\coordinate (rpc1-nw) at ($ (rpc-client.north west) + (-0.3, 0.3 + \titlepad) $);
|
||||
\coordinate (rpc1-ne) at ($ (rpc-client.north east) + ( 0.3, 0.3 + \titlepad) $);
|
||||
\coordinate (rpc1-sw) at ($ (rpc-client.south west) + (-0.3,-0.3) $);
|
||||
\coordinate (rpc1-se) at ($ (rpc-client.south east) + ( 0.3,-0.3) $);
|
||||
|
||||
\draw[draw,thick,dotted] (rpc1-nw) rectangle (rpc1-se);
|
||||
\node[rectangle,fill=white] at ($(rpc1-nw)!0.5!(rpc1-ne)$) (rpc1_label) {\textit{CausalRPC}};
|
||||
|
||||
\coordinate (rpc-bottom) at ($(rpc-client.south west)!0.5!(rpc-client.south east) + (0, -0.3)$);
|
||||
|
||||
\node[layer, green, below = \layer of rpc-bottom] (irmin) {Irmin};
|
||||
\node[layer, green, below = \layer of irmin] (git) {Ocaml-git};
|
||||
\node[halflayer, green, below = 2*\layer of git, xshift=-1.325cm] (Da) {File system};
|
||||
\node[halflayer, fill=white, below = 2*\layer of git, xshift= 1.325cm] (Db) {Network stack};
|
||||
|
||||
% Lines down the left
|
||||
\coordinate (lline) at (rpc3a);
|
||||
\draw[->] (lline |- 0, 0 |- client-app.south) -- (lline |- 0, 0 |- rpc1.north);
|
||||
\draw[->] (lline |- 0, 0 |- rpc1.south) -- (lline |- 0, 0 |- rpc2.north);
|
||||
\draw[->] (lline |- 0, 0 |- rpc2.south) -- (lline |- 0, 0 |- rpc3a.north);
|
||||
\draw[->] (lline |- 0, 0 |- rpc3a.south) -- (lline |- 0, 0 |- irmin.north);
|
||||
\draw[->] (lline |- 0, 0 |- irmin.south) -- (lline |- 0, 0 |- git.north);
|
||||
|
||||
% Lines down the right
|
||||
\coordinate (rline) at (rpc3b);
|
||||
\draw[->] (rline |- 0, 0 |- rpc1.north) -- (rline |- 0, 0 |- client-app.south);
|
||||
\draw[->] (rline |- 0, 0 |- rpc2.north) -- (rline |- 0, 0 |- rpc1.south);
|
||||
\draw[->] (rline |- 0, 0 |- rpc3a.north) -- (rline |- 0, 0 |- rpc2.south);
|
||||
\draw[->] (rline |- 0, 0 |- irmin.north) -- (rline |- 0, 0 |- rpc3a.south);
|
||||
\draw[->] (rline |- 0, 0 |- git.north) -- (rline |- 0, 0 |- irmin.south);
|
||||
\end{scope}
|
||||
|
||||
\begin{scope}[on background layer, local bounding box=client-kernel]
|
||||
\fill[gray!15] ($ (Da.north west) + (-\layer,\layer) $) rectangle ($ (Db.south east) + (\layer, -\layer) $);
|
||||
\end{scope}
|
||||
|
||||
\draw[-, gray, dashed] (client-kernel.north west) -- (client-kernel.north east);
|
||||
|
||||
\coordinate (client-nw) at ($ (client.north west) + (-\inner, \inner + \titlepad) $);
|
||||
\coordinate (client-ne) at ($ (client.north east) + ( \inner, \inner + \titlepad) $);
|
||||
\coordinate (client-sw) at ($ (client.south west) + (-\inner,-\inner) $);
|
||||
\coordinate (client-se) at ($ (client.south east) + ( \inner,-\inner) $);
|
||||
|
||||
\draw[draw, thick] (client-nw) rectangle (client-se);
|
||||
\node[rectangle, fill=white] at ($(client-nw)!0.5!(client-ne)$) (client_label) {\normalsize\textbf{CausalRPC client}};
|
||||
|
||||
\coordinate (fs-left) at ($(Da.north west)!0.3333!(Da.north east)$);
|
||||
\coordinate (fs-right) at ($(Da.north west)!0.6667!(Da.north east)$);
|
||||
\draw[->] (fs-left |- 0, 0 |- git.south) -- (fs-left |- 0, 0 |- Da.north);
|
||||
\draw[<-] (fs-right |- 0, 0 |- git.south) -- (fs-right |- 0, 0 |- Da.north);
|
||||
|
||||
\coordinate (net-left) at ($(Db.north west)!0.3333!(Db.north east)$);
|
||||
\coordinate (net-right) at ($(Db.north west)!0.6667!(Db.north east)$);
|
||||
\draw[->] (net-left |- 0, 0 |- git.south) -- (net-left |- 0, 0 |- Db.north);
|
||||
\draw[<-] (net-right |- 0, 0 |- git.south) -- (net-right |- 0, 0 |- Db.north);
|
||||
|
||||
% \begin{scope}[local bounding box=cloud,shift={($(cloud_center) + (0, -0.05)$)}, rotate=0, scale=0.5]
|
||||
% \draw[fill=white,thick] (-1.6,-0.7) .. controls (-2.3,-1.1)
|
||||
% and (-2.7,0.3) .. (-1.7,0.3) .. controls (-1.6,0.7)
|
||||
% and (-1.2,0.9) .. (-0.8,0.7) .. controls (-0.5,1.5)
|
||||
% and (0.6,1.3) .. (0.7,0.5) .. controls (1.5,0.4)
|
||||
% and (1.2,-1) .. (0.4,-0.6) .. controls (0.2,-1)
|
||||
% and (-0.2,-1) .. (-0.5,-0.7) .. controls (-0.9,-1)
|
||||
% and (-1.3,-1) .. cycle;
|
||||
% \end{scope}
|
||||
|
||||
\coordinate (yheight) at ($ (std-rpc-client.east) + (0, -1) $);
|
||||
\coordinate (trans-arrow-l) at (std-client-kernel.east |- 0, 0 |- yheight);
|
||||
\coordinate (trans-arrow-r) at (client-kernel.west |- 0, 0 |- yheight);
|
||||
\draw[very thick, ->] ($(trans-arrow-l) + (0.5, 0)$) -- node[above, text width = 4cm, align = center, yshift=3mm] {\normalsize\emph{Expose underlying \\[1mm] statefulness}} ($(trans-arrow-r) + (-0.5,0)$);
|
||||
|
||||
\end{tikzpicture}
|
||||
\end{document}
|
Before Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 2.2 MiB |
BIN
graphs/fib_launch_times.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
graphs/namespace_stacked_times.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
graphs/namespace_times.png
Normal file
After Width: | Height: | Size: 7.5 KiB |
BIN
graphs/tls-server-requests-per-second.png
Normal file
After Width: | Height: | Size: 37 KiB |
56
report.tex
@ -145,7 +145,9 @@ Words outside text (captions, etc.): 128
|
||||
|
||||
\chapter*{Abstract}
|
||||
|
||||
\todo{Write abstract.}
|
||||
The important of privilege separation - separating the parts of an application with the most risk of attack from the parts with the most reward for an attacker - for protection of resources in a modern operating system cannot be understated. As Linux has grown into the behemoth of an operating system that it is today, many privileges and attack vectors have been enabled, large amounts of which are given passively to new processes. New methods for protecting applications and processes have come along at nearly the same rate. This paper presents void processes: a framework to restrict Linux processes, removing access to ambient resources by default and providing APIs to systematically unlock abilities that applications require. Void processes solve the problem of needing to know what your privilege is in order to reduce it, as an application developer can begin from a clean slate.
|
||||
|
||||
This project built a system, the void orchestrator, to enable application developers to build upwards from a point of zero-privilege, rather than removing privilege that they don't need. This report gives the background and technical details of how to achieve this on modern Linux. I present a summary of the privilege separation techniques currently employed in production and details on how to create an empty set of namespaces to remove all privilege in Linux, a technique named entering the void. The shortcomings of Linux when creating empty namespaces are discussed, before setting forth the methods for re-adding features in each of these domains. Finally, two example applications are built and their performance evaluated to show the utility of the system. This report aims to demonstrate the value of a paradigm shift from reducing an arbitrary amount of privilege to adding only what is necessary.
|
||||
|
||||
\ifsubmission\else
|
||||
% not included in submission for blind marking:
|
||||
@ -172,7 +174,7 @@ support of \ldots [optional]
|
||||
|
||||
Newly spawned processes on modern Linux are exposed to a myriad of attack vectors and privilege, whether the hundreds of system calls available, \texttt{procfs}, exposure of filesystem objects, or the ability to connect to arbitrary hosts on the Internet. This paper presents void processes: a framework to restrict Linux processes, removing access to ambient resources by default and providing APIs to systematically unlock abilities that applications require. Explicit privilege designation with void processes could have saved many applications from the threat of CVE-2021-44228 with Log4j2 by ensuring that the processes which do dangerous user data processing are sufficiently deprivileged to prevent remote code execution (§\ref{lst:fibonacci-application-spec}). Moreover, adding explicit privilege with each change encourages consideration of privilege separation whenever new privilege is added, rather than when flaws are exposed.
|
||||
|
||||
This project built a system, the void orchestrator, to enable application developers to build upwards from a point of zero-privilege, rather than removing privilege that they don't need. This report gives the background and technical details of how to achieve this on modern Linux. I present a summary of the privilege separation techniques currently employed in production (§\ref{chap:priv-sep}) and details on how to create an empty set of namespaces to remove all privilege in Linux (§\ref{chap:entering-the-void}), a technique named entering the void. The shortcomings of the kernel are discussed (§\ref{sec:voiding-mount},§\ref{sec:voiding-user},§\ref{sec:voiding-cgroup}), before discussing how to re-add features to the kernel in each of these domains (§\ref{chap:filling-the-void}). Finally, three example applications are built (§\ref{chap:building-apps}) and evaluated (§\ref{chap:evaluation}) to show the utility of the system. This report aims to demonstrate the value of a paradigm shift from reducing an arbitrary amount of privilege to adding only what is necessary.
|
||||
This project built a system, the void orchestrator, to enable application developers to build upwards from a point of zero-privilege, rather than removing privilege that they don't need. This report gives the background and technical details of how to achieve this on modern Linux. I present a summary of the privilege separation techniques currently employed in production (§\ref{chap:priv-sep}) and details on how to create an empty set of namespaces to remove all privilege in Linux (§\ref{chap:entering-the-void}), a technique named entering the void. The shortcomings of Linux when creating empty namespaces are discussed (§\ref{sec:voiding-mount},§\ref{sec:voiding-user},§\ref{sec:voiding-cgroup}), before setting forth the methods for re-adding features in each of these domains (§\ref{chap:filling-the-void}). Finally, two example applications are built (§\ref{chap:building-apps}) and evaluated (§\ref{chap:evaluation}) to show the utility of the system. This report aims to demonstrate the value of a paradigm shift from reducing an arbitrary amount of privilege to adding only what is necessary.
|
||||
|
||||
Much prior work exists in the space of privilege separation, including: virtual machines (§\ref{sec:priv-sep-another-machine}); containers (§\ref{sec:priv-sep-perspective}); object capabilities (§\ref{sec:priv-sep-ownership}); unikernels; and applications which run directly on a Linux host, potentially employing privilege separation of their own (§\ref{sec:priv-sep-process}, §\ref{sec:priv-sep-time}). These alternative environments are plotted in Figure \ref{fig:attack-vs-changes}, in which the difference between applications written for the environment and the attack surface remaining are compared. Void processes contribute a strong compromise between providing a rich Linux-like interface for applications, reducing necessary code changes, and significantly reducing the attack surface (demonstrated in §\ref{chap:entering-the-void}).
|
||||
|
||||
@ -202,8 +204,8 @@ In 2003, privilege separation was added to the \texttt{syslogd} daemon of OpenBS
|
||||
|
||||
\begin{figure}
|
||||
\centering
|
||||
\includegraphics[width=0.4\textwidth]{figures/openbsd-syslogd-privsep.png}
|
||||
\caption{Data flow with the two processes in OpenBSD's privilege separated syslogd design.}
|
||||
\includestandalone[width=0.4\textwidth]{diagrams/openbsd-syslogd-privsep}
|
||||
\caption{Separation of privileged access from untrusted user data in OpenBSD's privilege separated syslogd design compared to the previous. The process which handles untrusted data is separated from the privileged process and uses RPC to communicate.}
|
||||
\label{fig:openbsd-syslogd-privsep}
|
||||
\end{figure}
|
||||
|
||||
@ -827,19 +829,11 @@ As C does not have high-level language features for multi-entrypoint application
|
||||
Rather than presenting the complete applications as shown in the previous two sections, the TLS server presents instead a case study on designing applications from the ground up to run as void processes. The thought process behind data flow design and taking advantage of the more advanced void orchestrator features is given. This results in the process separation presented in Figure \ref{fig:tls-server-processes}. First we must accept TCP requests from the end user (§\ref{sec:building-tls-tcp-listener}). Then, to be able to check that all is working so far, we respond to these requests (§\ref{sec:building-tls-http-handler}). Finally, we add an encryption layer using TLS (\ref{sec:building-tls-tls-handler}). This results in a functional TLS file server with strong privilege separation, with each stage having no more privilege than it needs.
|
||||
|
||||
\begin{figure}
|
||||
\label{fig:tls-server-processes}
|
||||
\centering
|
||||
\includestandalone[width=0.8\textwidth]{diagrams/tls-server-processes}
|
||||
|
||||
\caption{The final process design for a TLS server running under the void orchestrator. The figure is split into processes running void orchestrator code and processes running user code. Arrows represent a passing of privilege from one process to another.}
|
||||
|
||||
\centering
|
||||
\includegraphics[width=\columnwidth]{figures/tls-server-splitting.png}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}
|
||||
\centering
|
||||
\includestandalone[width=0.9\textwidth]{diagrams/tls-server-processes}
|
||||
|
||||
\caption{The final process design for a TLS server running under the void orchestrator. The figure is split into processes running void orchestrator code and processes running user code. Arrows represent a passing of privilege from one process to another (tikzified).}
|
||||
\label{fig:tls-server-processes-tikz}
|
||||
\label{fig:tls-server-processes}
|
||||
\end{figure}
|
||||
|
||||
\subsection{TCP listener}
|
||||
@ -969,12 +963,38 @@ Privilege separation often presents a trade-off between performance and security
|
||||
\section{Startup costs}
|
||||
\label{sec:evaluation-startup}
|
||||
|
||||
\todo{Plot void creation costs in isolation.}
|
||||
Every void process created requires a set of 7 unique namespaces, which is a lot of work compared to a standard \texttt{fork(2)}/\texttt{vfork(2)} call. Here I evaluated the overhead of such operations, first on the raw clone calls, and secondly on launching the basic Fibonacci application (§\ref{sec:building-fib}).
|
||||
|
||||
\begin{figure}
|
||||
\centering
|
||||
\includegraphics[width=0.7\textwidth]{graphs/namespace_times.png}
|
||||
\caption{Performance of making the \texttt{clone(2)} system call with varying namespace creation flags. The test is run in a tight compiled C loop with high precision timings taken before and after each new process is cloned and waited for. \texttt{clone(2)} presents very noisy results on a system with background activity.}
|
||||
\label{fig:namespace-times}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}
|
||||
\centering
|
||||
\includegraphics[width=0.8\textwidth]{graphs/namespace_stacked_times.png}
|
||||
\caption{Performance of making the \texttt{clone(2)} system call with increasing amounts of namespace creation flags. The effects of Figure \ref{fig:namespace-times} are amplified when creating multiple namespaces in a single call this frequently. There is a clear divide between the time taken for user, pid, uts, and cgroup namespaces and ipc, ns and net namespaces.}
|
||||
\label{fig:namespace-stacked-times}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}
|
||||
\centering
|
||||
\includegraphics[width=0.8\textwidth]{graphs/fib_launch_times.png}
|
||||
\caption{A box plot comparing the performance of the Fibonacci example (§\ref{sec:building-fib} under the shim and called directly. The median time to run under the shim is approximately 800\% the time without. The inter-quartile range and range of results is also much larger.}
|
||||
\label{fig:namespace-times}
|
||||
\end{figure}
|
||||
|
||||
\section{Runtime impact}
|
||||
\label{sec:evaluation-runtime}
|
||||
|
||||
\todo{Plot the impact of void processes against varying levels of privilege separation.}
|
||||
\begin{figure}
|
||||
\centering
|
||||
\includegraphics[width=0.8\textwidth]{graphs/tls-server-requests-per-second.png}
|
||||
\caption{\texttt{a2bench} requests per second results over 10 seconds with 100 simultaneous requests on varying response sizes. As the response size increases, the gap between the \texttt{apache2} TLS web server and the void process TLS web server decreases.}
|
||||
\label{fig:namespace-times}
|
||||
\end{figure}
|
||||
|
||||
\section{Summary}
|
||||
|
||||
|