forked from openssh/openssh-portable
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathREADME.privsep
More file actions
173 lines (144 loc) · 7.99 KB
/
Copy pathREADME.privsep
File metadata and controls
173 lines (144 loc) · 7.99 KB
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
163
164
165
166
167
168
169
170
171
172
Privilege separation, or privsep, is a method in OpenSSH by which
operations that require root privilege are performed by a separate
privileged monitor process. Its purpose is to prevent privilege
escalation and mitigate attacks by:
- reducing the privileged attack surface by performing most
operations involving untrusted data in unprivileged code,
- facilitating OS-level sandboxing of the components that are most
exposed to attack,
- reducing information-sharing between privileged and
unprivileged code, and
- containing attacks as much as possible to the unprivileged
process, should they occur.
To achieve privilege separation in OpenSSH's sshd, the functions
it performs are split across three discrete binaries:
sshd is the main entry-point binary for the server. This binary
retains privilege but performs a very limited set of tasks: loading
and checking the configuration, listening for incoming connections
and monitoring the status of connections through the
pre-authentication phase of their lifecycle to implement the
MaxStartups and PerSourcePenalties features.
Apart from listening for and accepting connections, the sshd binary
does not handle untrusted, network-derived data; instead it forks and
executes the sshd-session binary for each new connection.
+---------------------------------------------------------------+
| |
| listening socket +-------------------+ |
| \--------------+ sshd (listener) | |
| +--------++---------+ |
| || |
| || fork+exec |
| || |
| +--------------++------------------+ |
| | sshd-session (preauth monitor) | |
| +--------------++------------------+ |
| || |
| || fork+exec |
| || |
| network socket +------------++--------------+ |
| \-----------+ sshd-auth (unprivileged) | |
| +------------++--------------+ |
| |
+---------------------------------------------------------------+
pre-authentication process structure
sshd-session initially acts as the privileged monitor process for
a connection before it completes authentication. During this phase,
it does not deal directly with network-derived data, but forks and
executes a third binary (sshd-auth, described next) to handle the
SSH protocol communication over the network socket. sshd-session
receives RPC messages from the sshd-auth subprocess when it needs
to perform privileged operations, such as verifying an account's
existence, signing with a host key, or checking a user's password.
The monitor process implements a loose state machine that enforces
the required structure and order of operations that sshd-auth may
request.
sshd-auth is the network-facing process that implements the initial
key agreement and authentication phase of the SSH protocol. It is
started with privilege, but will sandbox and/or chroot(2) itself
and drop privilege to an unprivileged account before processing
any network traffic. All operations that require privilege, such as
looking up user information, private key signatures, checking
passwords, etc are performed by RPC to the parent sshd-session
process. After authentication completes, sshd-auth serialises its
SSH protocol and connection state, exports this to the parent
sshd-session process and exits.
Communication between parent and child processes occurs over shared
file descriptors. Parent processes also monitor their children for
abnormal exit conditions, such as crashes or signalling via exit(3)
status. These conditions are used in sshd to implement the
PerSourcePenalties controls.
+---------------------------------------------------------------+
| |
| +---------------++------------------+ |
| | sshd-session (postauth monitor) | |
| +---------------++------------------+ |
| || |
| || fork |
| || |
| network socket +--------------++---------------+ |
| \-----------+ sshd-session (unprivileged) | |
| +--------------++---------------+ |
| |
+---------------------------------------------------------------+
post-authentication process structure
After authentication, sshd-session disconnects from its parent
listener sshd (which doesn't track connections after authentication
has succeeded) and forks again. The forked sshd-session child process
will drop privilege to that of the authenticated user, import the
previously-serialised connection state from sshd-auth and continue to
perform network and SSH protocol operations for the remainder of the
session.
The parent sshd-session process continues to act as a privileged
monitor process, performing actions that require privilege when
requested via RPC. These operations include allocating PTYs and
signing key re-exchange messages.
In portable OpenSSH several compile-time options affect privilege
separation:
--with-sandbox=style
Controls the sandboxing implementation used by sshd-auth. OS level
sandboxing is supported on a number of platforms. A fallback
rlimit(2)-based sandbox provides some basic control on a wider set
of platforms. Most supported sandboxes are detected and enabled
automatically, so this option is mostly used to disable the sandbox
(this is handy when debugging or running under tools like
AddressSanitizer).
--with-privsep-user=user
Specifies the unprivileged user that sshd-auth will switch to
before it starts handling untrusted data. This user must not be
shared with any other system service, should own no files, should
have a locked password, a shell that denies access (such as
/bin/nologin or /bin/false) and the home directory set to the
privilege separation path. For most platforms the default user is
"sshd".
--with-privsep-path=/path
Controls the directory that sshd-auth will chroot(2) to before
dropping privileges. This directory should be empty, not shared
with other system accounts and not readable or writable by the
sandbox user. The default privsep path is "/var/empty".
You should do something like the following to prepare the privsep
preauth environment:
# mkdir /var/empty
# chown root:sys /var/empty
# chmod 755 /var/empty
# groupadd sshd
# useradd -g sshd -c 'sshd privsep' -d /var/empty -s /bin/false sshd
On some platforms, only the pre-authentication part of privsep is
supported, and the post-authentication part is disabled due to lack
of support from the operating system.
This is an example process list for a connection in the
pre-authentication phase:
PID PPID UID CMD
1436 1 0 sshd: /usr/sbin/sshd -D [listener] 1 of 10-100 startups
47077 1436 0 sshd-session: djm [priv]
47078 47077 107 sshd-auth: djm [net]
Where process 1436 is the listener, 47077 is the privileged
sshd-session monitor process and 47078 is the unprivileged,
network-facing sshd-auth process.
And in the post-authentication phase:
PID PPID UID CMD
47077 1436 0 sshd-session: djm [priv]
47091 47077 1000 sshd-session: djm@pts/1
47092 47091 1000 -bash
Where process 47077 continues its role as a privileged monitor,
47091 is the user-privileged network-facing post-authentication
process and 47092 is the user shell started for the session.