1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
|
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="Content-Language" content="en" />
<title>s6-networking: the s6-sudod program</title>
<meta name="Description" content="s6-networking: the s6-sudod program" />
<meta name="Keywords" content="s6-networking s6-sudod sudo setuid suid unix privilege gain getpeereid server" />
<!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
</head>
<body>
<p>
<a href="index.html">s6-networking</a><br />
<a href="http://skarnet.org/software/">Software</a><br />
<a href="http://skarnet.org/">skarnet.org</a>
</p>
<h1> The <tt>s6-sudod</tt> program </h1>
<p>
<tt>s6-sudod</tt> receives command-line arguments, environment variables
and standard descriptors from a peer <a href="s6-sudoc.html">s6-sudoc</a>
program over a Unix socket, then forks another program.
</p>
<h2> Interface </h2>
<pre>
s6-sudod [ -0 ] [ -1 ] [ -2 ] [ -s ] [ -t <em>timeout</em> ] [ <em>sargv...</em> ]
</pre>
<ul>
<li> s6-sudod gets 3 file descriptors via fd-passing over a Unix socket that
must be open on its descriptors 0 and 1. (The received descriptors will be the
stdin, stdout and stderr of the server program.) It expects a
<a href="s6-sudoc.html">s6-sudoc</a> process to be sending them on the
client side. </li>
<li> It also receives a list of command-line arguments <em>cargv...</em>, and
an environment <em>clientenv</em>. </li>
<li> s6-sudod forks and executes <em>sargv...</em> <em>cargv</em>...
The client command line is appended to the server command line. </li>
<li> s6-sudod waits for its child to exit and transmits its exit code
to the peer <a href="s6-sudoc.html">s6-sudoc</a> process. It then exits 0. </li>
</ul>
<h2> Environment </h2>
<p>
s6-sudod transmits its own environment to its child, plus the environment sent
by <a href="s6-sudoc.html">s6-sudoc</a>, filtered in the following manner:
for every variable sent by <a href="s6-sudoc.html">s6-sudoc</a>, if the
variable is <strong>present but empty</strong> in s6-sudod's environment, then
its value is overriden by the value given by s6-sudoc. A variable that is
already nonempty, or that doesn't exist, in s6-sudod's environment, will not
be transmitted to the child.
</p>
<h2> Options </h2>
<ul>
<li> <tt>-0</tt> : do not inherit stdin from s6-sudoc. The child will be
run with its stdin pointing to <tt>/dev/null</tt> instead. </li>
<li> <tt>-1</tt> : do not inherit stdout from s6-sudoc. The child will be
run with its stdout pointing to <tt>/dev/null</tt> instead. </li>
<li> <tt>-2</tt> : do not inherit stderr from s6-sudoc. The child will be
run with its stderr being a copy of s6-sudod's stderr instead. (This is useful
to still log the child's error messages without sending them to the client.) </li>
<li> <tt>-t <em>timeout</em></tt> : if s6-sudod has not
received all the needed data from the client after <em>timeout</em>
milliseconds, it will exit without spawning a child. By default, <em>timeout</em>
is 0, meaning infinite. This mechanism exists to protect the server from
malicious or buggy clients that would uselessly consume resources. </li>
</ul>
<h2> Usage example </h2>
<p>
The typical use of s6-sudod is in a
<a href="localservice.html">local service</a> with a
<a href="s6-ipcserver.html">s6-ipcserver</a> process listening on a Unix
socket, a <a href="s6-ipcserver-access.html">s6-ipcserver-access</a> process
performing client authentication and access control, and possibly a
<a href="http://skarnet.org/software/s6/s6-envdir.html">s6-envdir</a>
process setting up the environment variables that will be accepted by
s6-sudod. The following script, meant to be a <em>run script</em> in a
<a href="http://skarnet.org/software/s6/servicedir.html">service directory</a>,
will set up a privileged program:
</p>
<pre>
#!/command/execlineb -P
fdmove -c 2 1
s6-envuidgid serveruser
s6-ipcserver -U -- serversocket
s6-ipcserver-access -v2 -l0 -i rules --
exec -c
s6-envdir env
s6-sudod
sargv
</pre>
<ul>
<li> <a href="http://skarnet.org/software/execline/execlineb.html">execlineb</a>
executes the script. </li>
<li> <a href="http://skarnet.org/software/execline/fdmove.html">fdmove</a> makes
sure the script's error messages are sent to the service's logger. </li>
<li> <a href="http://skarnet.org/software/s6/s6-envuidgid.html">s6-envuidgid</a>
sets the UID, GID and GIDLIST environment variables for s6-ipcserver to interpret. </li>
<li> <a href="s6-ipcserver.html">s6-ipcserver</a> binds to <em>serversocket</em>
and drops its privileges to those of <em>serveruser</em>. Then, for every client
connecting to <em>serversocket</em>:
<ul>
<li> <a href="s6-ipcserver-access.html">s6-ipcserver-access</a> checks the
client's credentials according to the rules in directory <em>rules</em>.
<li> <a href="http://skarnet.org/software/execline/exec.html">exec -c</a>
clears the environment. </li>
<li> <a href="http://skarnet.org/software/s6/s6-envdir.html">s6-envdir</a>
sets environment variables according to the directory <em>env</em>. You can
make sure that a variable VAR will be present but empty by performing
<tt>echo > env/VAR</tt>. (A single newline is interpreted by s6-envdir as
an empty variable; whereas if <tt>env/VAR</tt> is totally empty, then the
VAR variable will be removed from the environment.) </li>
<li> s6-sudod reads a command line <em>cargv</em>, a client environment
and file descriptors over the socket. </li>
<li> s6-sudod spawns <tt>sargv cargv</tt>. </li>
</ul>
</ul>
<p>
This means that user <em>clientuser</em> running
<tt><a href="s6-sudo.html">s6-sudo</a> serversocket cargv</tt> will be
able, if authorized by the configuration in <em>rules</em>, to run
<tt>sargv cargv</tt> as user <em>serveruser</em>, with stdin,
stdout, stderr and the environment variables properly listed in <em>env</em>
transmitted to <em>sargv</em>.
</p>
<h2> Notes </h2>
<ul>
<li> If s6-sudoc is killed, or exits after <em>timeoutrun</em> milliseconds,
while the server program is still running, s6-sudod will send a SIGTERM and a
SIGCONT to its child, then exit 1. However, sending a SIGTERM to the child
does not guarantee that it will die; and
if it keeps running, it might still read from the file that
was s6-sudoc's stdin, or write to the files that were s6-sudod's stdout or
stderr. <strong>This is a potential security risk</strong>.
Administrators should audit their server programs to make sure this does not
happen. </li>
<li> More generally, anything using signals or terminals will not be
handled transparently by the s6-sudoc + s6-sudod mechanism. The mechanism
was designed to allow programs to gain privileges in specific situations:
short-lived, simple, noninteractive processes. It was not designed to emulate
the full suid functionality and will not go out of its way to do so. </li>
<li> <em>sargv</em> may be empty. In that case, the client is in complete
control of the command line executed as <em>serveruser</em>. This setup is
permitted by s6-sudod, but it is very dangerous, and extreme attention should
be paid to the construction of the s6-ipcserver-access rules. </li>
</ul>
</body>
</html>
|