1 From b09b8dcdda058d6f237baf50810f13e5b6aa47bb Mon Sep 17 00:00:00 2001
2 From: Damien Miller <djm@mindrot.org>
3 Date: Fri, 8 Jan 2016 14:24:56 +1100
4 Subject: [PATCH 02/36] Support Illumos/Solaris fine-grained privileges
5
6 Includes a pre-auth privsep sandbox and several pledge()
7 emulations. bz#2511, patch by Alex Wilson.
8
9 ok dtucker@
10 ---
11 Makefile.in | 5 +-
12 configure.ac | 38 +++++++++++++-
13 mux.c | 4 ++
14 openbsd-compat/port-solaris.c | 114 ++++++++++++++++++++++++++++++++++++++++++
15 openbsd-compat/port-solaris.h | 3 ++
16 platform-pledge.c | 71 ++++++++++++++++++++++++++
17 platform.h | 5 ++
18 sandbox-solaris.c | 107 +++++++++++++++++++++++++++++++++++++++
19 sftp-server.c | 3 ++
20 ssh-agent.c | 2 +
21 uidswap.c | 18 ++++---
22 11 files changed, 360 insertions(+), 10 deletions(-)
23 create mode 100644 platform-pledge.c
24 create mode 100644 sandbox-solaris.c
25
26 diff --git a/Makefile.in b/Makefile.in
27 index 40cc7aa..8494713 100644
28 --- a/Makefile.in
29 +++ b/Makefile.in
30 @@ -91,7 +91,8 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
31 sc25519.o ge25519.o fe25519.o ed25519.o verify.o hash.o blocks.o \
32 kex.o kexdh.o kexgex.o kexecdh.o kexc25519.o \
33 kexdhc.o kexgexc.o kexecdhc.o kexc25519c.o \
34 - kexdhs.o kexgexs.o kexecdhs.o kexc25519s.o
35 + kexdhs.o kexgexs.o kexecdhs.o kexc25519s.o \
36 + platform-pledge.o
37
38 SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
39 sshconnect.o sshconnect1.o sshconnect2.o mux.o \
40 @@ -110,7 +111,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \
41 sftp-server.o sftp-common.o \
42 roaming_common.o roaming_serv.o \
43 sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \
44 - sandbox-seccomp-filter.o sandbox-capsicum.o
45 + sandbox-seccomp-filter.o sandbox-capsicum.o sandbox-solaris.o
46
47 MANPAGES = moduli.5.out scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-keysign.8.out ssh-pkcs11-helper.8.out sshd_config.5.out ssh_config.5.out
48 MANPAGES_IN = moduli.5 scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-keysign.8 ssh-pkcs11-helper.8 sshd_config.5 ssh_config.5
49 diff --git a/configure.ac b/configure.ac
50 index 9b05c30..b06cede 100644
51 --- a/configure.ac
52 +++ b/configure.ac
53 @@ -469,6 +469,11 @@ AC_CHECK_HEADERS([sys/un.h], [], [], [
54 SIA_MSG="no"
55 SPC_MSG="no"
56 SP_MSG="no"
57 +SPP_MSG="no"
58 +
59 +# Support for Solaris/Illumos privileges (this test is used by both
60 +# the --with-solaris-privs option and --with-sandbox=solaris).
61 +SOLARIS_PRIVS="no"
62
63 # Check for some target-specific stuff
64 case "$host" in
65 @@ -575,6 +580,8 @@ case "$host" in
66 LIBS="$LIBS /usr/lib/textreadmode.o"
67 AC_DEFINE([HAVE_CYGWIN], [1], [Define if you are on Cygwin])
68 AC_DEFINE([USE_PIPES], [1], [Use PIPES instead of a socketpair()])
69 + AC_DEFINE([NO_UID_RESTORATION_TEST], [1],
70 + [Define to disable UID restoration test])
71 AC_DEFINE([DISABLE_SHADOW], [1],
72 [Define if you want to disable shadow passwords])
73 AC_DEFINE([NO_X11_UNIX_SOCKETS], [1],
74 @@ -889,13 +896,18 @@ mips-sony-bsd|mips-sony-newsos4)
75 else
76 AC_MSG_RESULT([no])
77 fi
78 + AC_CHECK_FUNC([setppriv],
79 + [ AC_CHECK_HEADERS([priv.h], [
80 + SOLARIS_PRIVS="yes"
81 + ])
82 + ])
83 AC_ARG_WITH([solaris-contracts],
84 [ --with-solaris-contracts Enable Solaris process contracts (experimental)],
85 [
86 AC_CHECK_LIB([contract], [ct_tmpl_activate],
87 [ AC_DEFINE([USE_SOLARIS_PROCESS_CONTRACTS], [1],
88 [Define if you have Solaris process contracts])
89 - SSHDLIBS="$SSHDLIBS -lcontract"
90 + LIBS="$LIBS -lcontract"
91 SPC_MSG="yes" ], )
92 ],
93 )
94 @@ -905,10 +917,27 @@ mips-sony-bsd|mips-sony-newsos4)
95 AC_CHECK_LIB([project], [setproject],
96 [ AC_DEFINE([USE_SOLARIS_PROJECTS], [1],
97 [Define if you have Solaris projects])
98 - SSHDLIBS="$SSHDLIBS -lproject"
99 + LIBS="$LIBS -lproject"
100 SP_MSG="yes" ], )
101 ],
102 )
103 + AC_ARG_WITH([solaris-privs],
104 + [ --with-solaris-privs Enable Solaris/Illumos privileges (experimental)],
105 + [
106 + AC_MSG_CHECKING([for Solaris/Illumos privilege support])
107 + if test "x$SOLARIS_PRIVS" = "xyes" ; then
108 + AC_MSG_RESULT([found])
109 + AC_DEFINE([NO_UID_RESTORATION_TEST], [1],
110 + [Define to disable UID restoration test])
111 + AC_DEFINE([USE_SOLARIS_PRIVS], [1],
112 + [Define if you have Solaris privileges])
113 + SPP_MSG="yes"
114 + else
115 + AC_MSG_RESULT([not found])
116 + AC_MSG_ERROR([*** must have support for Solaris privileges to use --with-solaris-privs])
117 + fi
118 + ],
119 + )
120 TEST_SHELL=$SHELL # let configure find us a capable shell
121 ;;
122 *-*-sunos4*)
123 @@ -3147,6 +3176,10 @@ elif test "x$sandbox_arg" = "xrlimit" || \
124 AC_MSG_ERROR([rlimit sandbox requires select to work with rlimit])
125 SANDBOX_STYLE="rlimit"
126 AC_DEFINE([SANDBOX_RLIMIT], [1], [Sandbox using setrlimit(2)])
127 +elif test "x$sandbox_arg" = "xsolaris" || \
128 + ( test -z "$sandbox_arg" && test "x$SOLARIS_PRIVS" = "xyes" ) ; then
129 + SANDBOX_STYLE="solaris"
130 + AC_DEFINE([SANDBOX_SOLARIS], [1], [Sandbox using Solaris/Illumos privileges])
131 elif test -z "$sandbox_arg" || test "x$sandbox_arg" = "xno" || \
132 test "x$sandbox_arg" = "xnone" || test "x$sandbox_arg" = "xnull" ; then
133 SANDBOX_STYLE="none"
134 @@ -4933,6 +4966,7 @@ echo " MD5 password support: $MD5_MSG"
135 echo " libedit support: $LIBEDIT_MSG"
136 echo " Solaris process contract support: $SPC_MSG"
137 echo " Solaris project support: $SP_MSG"
138 +echo " Solaris privilege support: $SPP_MSG"
139 echo " IP address in \$DISPLAY hack: $DISPLAY_HACK_MSG"
140 echo " Translate v4 in v6 hack: $IPV4_IN6_HACK_MSG"
141 echo " BSD Auth support: $BSD_AUTH_MSG"
142 diff --git a/mux.c b/mux.c
143 index e6136fd..8c2a53a 100644
144 --- a/mux.c
145 +++ b/mux.c
146 @@ -1889,6 +1889,8 @@ mux_client_request_session(int fd)
147 }
148 muxclient_request_id++;
149
150 + platform_pledge_mux();
151 +
152 signal(SIGHUP, control_client_sighandler);
153 signal(SIGINT, control_client_sighandler);
154 signal(SIGTERM, control_client_sighandler);
155 @@ -1996,6 +1998,8 @@ mux_client_request_stdio_fwd(int fd)
156 mm_send_fd(fd, STDOUT_FILENO) == -1)
157 fatal("%s: send fds failed", __func__);
158
159 + platform_pledge_mux();
160 +
161 debug3("%s: stdio forward request sent", __func__);
162
163 /* Read their reply */
164 diff --git a/openbsd-compat/port-solaris.c b/openbsd-compat/port-solaris.c
165 index 25382f1..962cd16 100644
166 --- a/openbsd-compat/port-solaris.c
167 +++ b/openbsd-compat/port-solaris.c
168 @@ -227,3 +227,117 @@ solaris_set_default_project(struct passwd *pw)
169 }
170 }
171 #endif /* USE_SOLARIS_PROJECTS */
172 +
173 +#ifdef USE_SOLARIS_PRIVS
174 +# ifdef HAVE_PRIV_H
175 +# include <priv.h>
176 +# endif
177 +
178 +void
179 +solaris_drop_privs_pinfo_net_fork_exec(void)
180 +{
181 + priv_set_t *pset = NULL, *npset = NULL;
182 +
183 + /*
184 + * Note: this variant avoids dropping DAC filesystem rights, in case
185 + * the process calling it is running as root and should have the
186 + * ability to read/write/chown any file on the system.
187 + *
188 + * We start with the basic set, then *add* the DAC rights to it while
189 + * taking away other parts of BASIC we don't need. Then we intersect
190 + * this with our existing PERMITTED set. In this way we keep any
191 + * DAC rights we had before, while otherwise reducing ourselves to
192 + * the minimum set of privileges we need to proceed.
193 + *
194 + * This also means we drop any other parts of "root" that we don't
195 + * need (e.g. the ability to kill any process, create new device nodes
196 + * etc etc).
197 + */
198 +
199 + if ((pset = priv_allocset()) == NULL ||
200 + (npset = priv_allocset()) == NULL)
201 + fatal("priv_allocset: %s", strerror(errno));
202 +
203 + priv_basicset(npset);
204 +
205 + if (priv_addset(npset, PRIV_FILE_CHOWN) != 0 ||
206 + priv_addset(npset, PRIV_FILE_DAC_READ) != 0 ||
207 + priv_addset(npset, PRIV_FILE_DAC_SEARCH) != 0 ||
208 + priv_addset(npset, PRIV_FILE_DAC_WRITE) != 0 ||
209 + priv_addset(npset, PRIV_FILE_OWNER) != 0)
210 + fatal("priv_addset: %s", strerror(errno));
211 +
212 + if (priv_delset(npset, PRIV_FILE_LINK_ANY) != 0 ||
213 + priv_delset(npset, PRIV_NET_ACCESS) != 0 ||
214 + priv_delset(npset, PRIV_PROC_EXEC) != 0 ||
215 + priv_delset(npset, PRIV_PROC_FORK) != 0 ||
216 + priv_delset(npset, PRIV_PROC_INFO) != 0 ||
217 + priv_delset(npset, PRIV_PROC_SESSION) != 0)
218 + fatal("priv_delset: %s", strerror(errno));
219 +
220 + if (getppriv(PRIV_PERMITTED, pset) != 0)
221 + fatal("getppriv: %s", strerror(errno));
222 +
223 + priv_intersect(pset, npset);
224 +
225 + if (setppriv(PRIV_SET, PRIV_PERMITTED, npset) != 0 ||
226 + setppriv(PRIV_SET, PRIV_LIMIT, npset) != 0 ||
227 + setppriv(PRIV_SET, PRIV_INHERITABLE, npset) != 0)
228 + fatal("setppriv: %s", strerror(errno));
229 +
230 + priv_freeset(pset);
231 + priv_freeset(npset);
232 +}
233 +
234 +void
235 +solaris_drop_privs_root_pinfo_net(void)
236 +{
237 + priv_set_t *pset = NULL;
238 +
239 + if ((pset = priv_allocset()) == NULL)
240 + fatal("priv_allocset: %s", strerror(errno));
241 +
242 + /* Start with "basic" and drop everything we don't need. */
243 + priv_basicset(pset);
244 +
245 + if (priv_delset(pset, PRIV_FILE_LINK_ANY) != 0 ||
246 + priv_delset(pset, PRIV_NET_ACCESS) != 0 ||
247 + priv_delset(pset, PRIV_PROC_INFO) != 0 ||
248 + priv_delset(pset, PRIV_PROC_SESSION) != 0)
249 + fatal("priv_delset: %s", strerror(errno));
250 +
251 + if (setppriv(PRIV_SET, PRIV_PERMITTED, pset) != 0 ||
252 + setppriv(PRIV_SET, PRIV_LIMIT, pset) != 0 ||
253 + setppriv(PRIV_SET, PRIV_INHERITABLE, pset) != 0)
254 + fatal("setppriv: %s", strerror(errno));
255 +
256 + priv_freeset(pset);
257 +}
258 +
259 +void
260 +solaris_drop_privs_root_pinfo_net_exec(void)
261 +{
262 + priv_set_t *pset = NULL;
263 +
264 + if ((pset = priv_allocset()) == NULL)
265 + fatal("priv_allocset: %s", strerror(errno));
266 +
267 + /* Start with "basic" and drop everything we don't need. */
268 + priv_basicset(pset);
269 +
270 + if (priv_delset(pset, PRIV_FILE_LINK_ANY) != 0 ||
271 + priv_delset(pset, PRIV_NET_ACCESS) != 0 ||
272 + priv_delset(pset, PRIV_PROC_EXEC) != 0 ||
273 + priv_delset(pset, PRIV_PROC_INFO) != 0 ||
274 + priv_delset(pset, PRIV_PROC_SESSION) != 0)
275 + fatal("priv_delset: %s", strerror(errno));
276 +
277 + if (setppriv(PRIV_SET, PRIV_PERMITTED, pset) != 0 ||
278 + setppriv(PRIV_SET, PRIV_LIMIT, pset) != 0 ||
279 + setppriv(PRIV_SET, PRIV_INHERITABLE, pset) != 0)
280 + fatal("setppriv: %s", strerror(errno));
281 +
282 + priv_freeset(pset);
283 +}
284 +
285 +#endif
286 diff --git a/openbsd-compat/port-solaris.h b/openbsd-compat/port-solaris.h
287 index cd442e7..b077e18 100644
288 --- a/openbsd-compat/port-solaris.h
289 +++ b/openbsd-compat/port-solaris.h
290 @@ -26,5 +26,8 @@ void solaris_contract_pre_fork(void);
291 void solaris_contract_post_fork_child(void);
292 void solaris_contract_post_fork_parent(pid_t pid);
293 void solaris_set_default_project(struct passwd *);
294 +void solaris_drop_privs_pinfo_net_fork_exec(void);
295 +void solaris_drop_privs_root_pinfo_net(void);
296 +void solaris_drop_privs_root_pinfo_net_exec(void);
297
298 #endif
299 diff --git a/platform-pledge.c b/platform-pledge.c
300 new file mode 100644
301 index 0000000..4a6ec15
302 --- /dev/null
303 +++ b/platform-pledge.c
304 @@ -0,0 +1,71 @@
305 +/*
306 + * Copyright (c) 2015 Joyent, Inc
307 + * Author: Alex Wilson <alex.wilson@joyent.com>
308 + *
309 + * Permission to use, copy, modify, and distribute this software for any
310 + * purpose with or without fee is hereby granted, provided that the above
311 + * copyright notice and this permission notice appear in all copies.
312 + *
313 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
314 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
315 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
316 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
317 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
318 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
319 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
320 + */
321 +
322 +#include "includes.h"
323 +
324 +#include <sys/types.h>
325 +
326 +#include <stdarg.h>
327 +#include <unistd.h>
328 +
329 +#include "platform.h"
330 +
331 +#include "openbsd-compat/openbsd-compat.h"
332 +
333 +/*
334 + * Drop any fine-grained privileges that are not needed for post-startup
335 + * operation of ssh-agent
336 + *
337 + * Should be as close as possible to pledge("stdio cpath unix id proc exec", ...)
338 + */
339 +void
340 +platform_pledge_agent(void)
341 +{
342 +#ifdef USE_SOLARIS_PRIVS
343 + /*
344 + * Note: Solaris priv dropping is closer to tame() than pledge(), but
345 + * we will use what we have.
346 + */
347 + solaris_drop_privs_root_pinfo_net();
348 +#endif
349 +}
350 +
351 +/*
352 + * Drop any fine-grained privileges that are not needed for post-startup
353 + * operation of sftp-server
354 + */
355 +void
356 +platform_pledge_sftp_server(void)
357 +{
358 +#ifdef USE_SOLARIS_PRIVS
359 + solaris_drop_privs_pinfo_net_fork_exec();
360 +#endif
361 +}
362 +
363 +/*
364 + * Drop any fine-grained privileges that are not needed for the post-startup
365 + * operation of the SSH client mux
366 + *
367 + * Should be as close as possible to pledge("stdio proc tty", ...)
368 + */
369 +void
370 +platform_pledge_mux(void)
371 +{
372 +#ifdef USE_SOLARIS_PRIVS
373 + solaris_drop_privs_root_pinfo_net_exec();
374 +#endif
375 +}
376 diff --git a/platform.h b/platform.h
377 index 1c7a45d..e687c99 100644
378 --- a/platform.h
379 +++ b/platform.h
380 @@ -31,3 +31,8 @@ void platform_setusercontext_post_groups(struct passwd *);
381 char *platform_get_krb5_client(const char *);
382 char *platform_krb5_get_principal_name(const char *);
383 int platform_sys_dir_uid(uid_t);
384 +
385 +/* in platform-pledge.c */
386 +void platform_pledge_agent(void);
387 +void platform_pledge_sftp_server(void);
388 +void platform_pledge_mux(void);
389 diff --git a/sandbox-solaris.c b/sandbox-solaris.c
390 new file mode 100644
391 index 0000000..98714e1
392 --- /dev/null
393 +++ b/sandbox-solaris.c
394 @@ -0,0 +1,107 @@
395 +/*
396 + * Copyright (c) 2015 Joyent, Inc
397 + * Author: Alex Wilson <alex.wilson@joyent.com>
398 + *
399 + * Permission to use, copy, modify, and distribute this software for any
400 + * purpose with or without fee is hereby granted, provided that the above
401 + * copyright notice and this permission notice appear in all copies.
402 + *
403 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
404 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
405 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
406 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
407 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
408 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
409 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
410 + */
411 +
412 +#include "includes.h"
413 +
414 +#ifdef SANDBOX_SOLARIS
415 +#ifndef USE_SOLARIS_PRIVS
416 +# error "--with-solaris-privs must be used with the Solaris sandbox"
417 +#endif
418 +
419 +#include <sys/types.h>
420 +
421 +#include <errno.h>
422 +#include <stdarg.h>
423 +#include <stdio.h>
424 +#include <stdlib.h>
425 +#include <string.h>
426 +#include <unistd.h>
427 +#ifdef HAVE_PRIV_H
428 +# include <priv.h>
429 +#endif
430 +
431 +#include "log.h"
432 +#include "ssh-sandbox.h"
433 +#include "xmalloc.h"
434 +
435 +struct ssh_sandbox {
436 + priv_set_t *pset;
437 +};
438 +
439 +struct ssh_sandbox *
440 +ssh_sandbox_init(struct monitor *monitor)
441 +{
442 + struct ssh_sandbox *box = NULL;
443 +
444 + box = xcalloc(1, sizeof(*box));
445 + box->pset = priv_allocset();
446 +
447 + if (box->pset == NULL) {
448 + free(box);
449 + return NULL;
450 + }
451 +
452 + /* Start with "basic" and drop everything we don't need. */
453 + priv_basicset(box->pset);
454 +
455 + /* Drop everything except the ability to use already-opened files */
456 + if (priv_delset(box->pset, PRIV_FILE_LINK_ANY) != 0 ||
457 + priv_delset(box->pset, PRIV_NET_ACCESS) != 0 ||
458 + priv_delset(box->pset, PRIV_PROC_EXEC) != 0 ||
459 + priv_delset(box->pset, PRIV_PROC_FORK) != 0 ||
460 + priv_delset(box->pset, PRIV_PROC_INFO) != 0 ||
461 + priv_delset(box->pset, PRIV_PROC_SESSION) != 0) {
462 + free(box);
463 + return NULL;
464 + }
465 +
466 + /* These may not be available on older Solaris-es */
467 +# if defined(PRIV_FILE_READ) && defined(PRIV_FILE_WRITE)
468 + if (priv_delset(box->pset, PRIV_FILE_READ) != 0 ||
469 + priv_delset(box->pset, PRIV_FILE_WRITE) != 0) {
470 + free(box);
471 + return NULL;
472 + }
473 +# endif
474 +
475 + return box;
476 +}
477 +
478 +void
479 +ssh_sandbox_child(struct ssh_sandbox *box)
480 +{
481 + if (setppriv(PRIV_SET, PRIV_PERMITTED, box->pset) != 0 ||
482 + setppriv(PRIV_SET, PRIV_LIMIT, box->pset) != 0 ||
483 + setppriv(PRIV_SET, PRIV_INHERITABLE, box->pset) != 0)
484 + fatal("setppriv: %s", strerror(errno));
485 +}
486 +
487 +void
488 +ssh_sandbox_parent_finish(struct ssh_sandbox *box)
489 +{
490 + priv_freeset(box->pset);
491 + box->pset = NULL;
492 + free(box);
493 +}
494 +
495 +void
496 +ssh_sandbox_parent_preauth(struct ssh_sandbox *box, pid_t child_pid)
497 +{
498 + /* Nothing to do here */
499 +}
500 +
501 +#endif /* SANDBOX_SOLARIS */
502 diff --git a/sftp-server.c b/sftp-server.c
503 index eac11d7..3877c03 100644
504 --- a/sftp-server.c
505 +++ b/sftp-server.c
506 @@ -1598,6 +1598,9 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw)
507 fatal("unable to make the process undumpable");
508 #endif /* defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE) */
509
510 + /* Drop any fine-grained privileges we don't need */
511 + platform_pledge_sftp_server();
512 +
513 if ((cp = getenv("SSH_CONNECTION")) != NULL) {
514 client_addr = xstrdup(cp);
515 if ((cp = strchr(client_addr, ' ')) == NULL) {
516 diff --git a/ssh-agent.c b/ssh-agent.c
517 index a335ea3..6c2f6d5 100644
518 --- a/ssh-agent.c
519 +++ b/ssh-agent.c
520 @@ -1402,6 +1402,8 @@ skip:
521 signal(SIGTERM, cleanup_handler);
522 nalloc = 0;
523
524 + platform_pledge_agent();
525 +
526 while (1) {
527 prepare_select(&readsetp, &writesetp, &max_fd, &nalloc, &tvp);
528 result = select(max_fd + 1, readsetp, writesetp, NULL, tvp);
529 diff --git a/uidswap.c b/uidswap.c
530 index 0702e1d..8bf6b24 100644
531 --- a/uidswap.c
532 +++ b/uidswap.c
533 @@ -134,7 +134,7 @@ temporarily_use_uid(struct passwd *pw)
534 void
535 permanently_drop_suid(uid_t uid)
536 {
537 -#ifndef HAVE_CYGWIN
538 +#ifndef NO_UID_RESTORATION_TEST
539 uid_t old_uid = getuid();
540 #endif
541
542 @@ -142,8 +142,14 @@ permanently_drop_suid(uid_t uid)
543 if (setresuid(uid, uid, uid) < 0)
544 fatal("setresuid %u: %.100s", (u_int)uid, strerror(errno));
545
546 -#ifndef HAVE_CYGWIN
547 - /* Try restoration of UID if changed (test clearing of saved uid) */
548 +#ifndef NO_UID_RESTORATION_TEST
549 + /*
550 + * Try restoration of UID if changed (test clearing of saved uid).
551 + *
552 + * Note that we don't do this on Cygwin, or on Solaris-based platforms
553 + * where fine-grained privileges are available (the user might be
554 + * deliberately allowed the right to setuid back to root).
555 + */
556 if (old_uid != uid &&
557 (setuid(old_uid) != -1 || seteuid(old_uid) != -1))
558 fatal("%s: was able to restore old [e]uid", __func__);
559 @@ -199,7 +205,7 @@ restore_uid(void)
560 void
561 permanently_set_uid(struct passwd *pw)
562 {
563 -#ifndef HAVE_CYGWIN
564 +#ifndef NO_UID_RESTORATION_TEST
565 uid_t old_uid = getuid();
566 gid_t old_gid = getgid();
567 #endif
568 @@ -227,7 +233,7 @@ permanently_set_uid(struct passwd *pw)
569 if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) < 0)
570 fatal("setresuid %u: %.100s", (u_int)pw->pw_uid, strerror(errno));
571
572 -#ifndef HAVE_CYGWIN
573 +#ifndef NO_UID_RESTORATION_TEST
574 /* Try restoration of GID if changed (test clearing of saved gid) */
575 if (old_gid != pw->pw_gid && pw->pw_uid != 0 &&
576 (setgid(old_gid) != -1 || setegid(old_gid) != -1))
577 @@ -241,7 +247,7 @@ permanently_set_uid(struct passwd *pw)
578 (u_int)pw->pw_gid);
579 }
580
581 -#ifndef HAVE_CYGWIN
582 +#ifndef NO_UID_RESTORATION_TEST
583 /* Try restoration of UID if changed (test clearing of saved uid) */
584 if (old_uid != pw->pw_uid &&
585 (setuid(old_uid) != -1 || seteuid(old_uid) != -1))
586 --
587 2.5.4 (Apple Git-61)
588