diff options
author | Damien Miller <djm@mindrot.org> | 2003-06-05 09:53:31 +1000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2003-06-05 09:53:31 +1000 |
commit | 5fe46a45c834bf2e336d979e2ae755b94e01d707 (patch) | |
tree | e65443bf5183b99f97a28f7209011f60c2a620e0 | |
parent | 0f68486a7673885ba2834af80fd14f1e3be16e8f (diff) |
- (djm) Implement paranoid priv dropping checks, based on:
"SetUID demystified" - Hao Chen, David Wagner and Drew Dean
Proceedings of USENIX Security Symposium 2002
-rw-r--r-- | ChangeLog | 5 | ||||
-rw-r--r-- | acconfig.h | 5 | ||||
-rw-r--r-- | configure.ac | 15 | ||||
-rw-r--r-- | includes.h | 1 | ||||
-rw-r--r-- | uidswap.c | 47 |
5 files changed, 64 insertions, 9 deletions
@@ -1,6 +1,9 @@ | |||
1 | 20030605 | 1 | 20030605 |
2 | - (djm) Support AI_NUMERICHOST in fake-getaddrinfo.c. Needed for recent | 2 | - (djm) Support AI_NUMERICHOST in fake-getaddrinfo.c. Needed for recent |
3 | canohost.c changes. | 3 | canohost.c changes. |
4 | - (djm) Implement paranoid priv dropping checks, based on: | ||
5 | "SetUID demystified" - Hao Chen, David Wagner and Drew Dean | ||
6 | Proceedings of USENIX Security Symposium 2002 | ||
4 | 7 | ||
5 | 20030604 | 8 | 20030604 |
6 | - (djm) Bug #573 - Remove unneeded Krb headers and compat goop. Patch from | 9 | - (djm) Bug #573 - Remove unneeded Krb headers and compat goop. Patch from |
@@ -462,4 +465,4 @@ | |||
462 | - Fix sshd BindAddress and -b options for systems using fake-getaddrinfo. | 465 | - Fix sshd BindAddress and -b options for systems using fake-getaddrinfo. |
463 | Report from murple@murple.net, diagnosis from dtucker@zip.com.au | 466 | Report from murple@murple.net, diagnosis from dtucker@zip.com.au |
464 | 467 | ||
465 | $Id: ChangeLog,v 1.2782 2003/06/04 23:48:32 djm Exp $ | 468 | $Id: ChangeLog,v 1.2783 2003/06/04 23:53:42 djm Exp $ |
diff --git a/acconfig.h b/acconfig.h index 9d6008e60..1f5109ba1 100644 --- a/acconfig.h +++ b/acconfig.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $Id: acconfig.h,v 1.155 2003/06/03 00:14:28 djm Exp $ */ | 1 | /* $Id: acconfig.h,v 1.156 2003/06/04 23:53:31 djm Exp $ */ |
2 | 2 | ||
3 | #ifndef _CONFIG_H | 3 | #ifndef _CONFIG_H |
4 | #define _CONFIG_H | 4 | #define _CONFIG_H |
@@ -8,6 +8,9 @@ | |||
8 | 8 | ||
9 | @TOP@ | 9 | @TOP@ |
10 | 10 | ||
11 | /* Define if your platform breaks doing a seteuid before a setuid */ | ||
12 | #undef SETEUID_BREAKS_SETUID | ||
13 | |||
11 | /* Define to a Set Process Title type if your system is */ | 14 | /* Define to a Set Process Title type if your system is */ |
12 | /* supported by bsd-setproctitle.c */ | 15 | /* supported by bsd-setproctitle.c */ |
13 | #undef SPT_TYPE | 16 | #undef SPT_TYPE |
diff --git a/configure.ac b/configure.ac index 21d764f2a..92f182ac0 100644 --- a/configure.ac +++ b/configure.ac | |||
@@ -1,4 +1,4 @@ | |||
1 | # $Id: configure.ac,v 1.125 2003/06/03 00:14:28 djm Exp $ | 1 | # $Id: configure.ac,v 1.126 2003/06/04 23:53:31 djm Exp $ |
2 | 2 | ||
3 | AC_INIT | 3 | AC_INIT |
4 | AC_CONFIG_SRCDIR([ssh.c]) | 4 | AC_CONFIG_SRCDIR([ssh.c]) |
@@ -439,7 +439,7 @@ AC_ARG_WITH(libs, | |||
439 | ) | 439 | ) |
440 | 440 | ||
441 | # Checks for header files. | 441 | # Checks for header files. |
442 | AC_CHECK_HEADERS(bstring.h crypt.h endian.h floatingpoint.h \ | 442 | AC_CHECK_HEADERS(bstring.h crypt.h endian.h features.h floatingpoint.h \ |
443 | getopt.h glob.h ia.h lastlog.h libgen.h limits.h login.h \ | 443 | getopt.h glob.h ia.h lastlog.h libgen.h limits.h login.h \ |
444 | login_cap.h maillock.h netdb.h netgroup.h \ | 444 | login_cap.h maillock.h netdb.h netgroup.h \ |
445 | netinet/in_systm.h paths.h pty.h readpassphrase.h \ | 445 | netinet/in_systm.h paths.h pty.h readpassphrase.h \ |
@@ -659,17 +659,18 @@ AC_ARG_WITH(tcp-wrappers, | |||
659 | 659 | ||
660 | dnl Checks for library functions. Please keep in alphabetical order | 660 | dnl Checks for library functions. Please keep in alphabetical order |
661 | AC_CHECK_FUNCS(\ | 661 | AC_CHECK_FUNCS(\ |
662 | arc4random __b64_ntop b64_ntop __b64_pton b64_pton basename bcopy \ | 662 | arc4random __b64_ntop b64_ntop __b64_pton b64_pton basename \ |
663 | bindresvport_sa clock fchmod fchown freeaddrinfo futimes \ | 663 | bcopy bindresvport_sa clock fchmod fchown freeaddrinfo futimes \ |
664 | gai_strerror getaddrinfo getcwd getgrouplist getnameinfo getopt \ | 664 | gai_strerror getaddrinfo getcwd getgrouplist getnameinfo getopt \ |
665 | getpeereid _getpty getrlimit getrusage getttyent glob inet_aton \ | 665 | getpeereid _getpty getrlimit getrusage getttyent glob inet_aton \ |
666 | inet_ntoa inet_ntop innetgr login_getcapbool md5_crypt memmove \ | 666 | inet_ntoa inet_ntop innetgr login_getcapbool md5_crypt memmove \ |
667 | mkdtemp mmap ngetaddrinfo nsleep ogetaddrinfo openlog_r openpty \ | 667 | mkdtemp mmap ngetaddrinfo nsleep ogetaddrinfo openlog_r openpty \ |
668 | pstat readpassphrase realpath recvmsg rresvport_af sendmsg \ | 668 | pstat readpassphrase realpath recvmsg rresvport_af sendmsg \ |
669 | setdtablesize setegid setenv seteuid setgroups setlogin setpcred \ | 669 | setdtablesize setegid setenv seteuid setgroups setlogin setpcred \ |
670 | setproctitle setresgid setreuid setrlimit setsid setvbuf sigaction \ | 670 | setproctitle setregid setresgid setresuid setreuid setrlimit \ |
671 | sigvec snprintf socketpair strerror strlcat strlcpy strmode strnvis \ | 671 | setsid setvbuf sigaction sigvec snprintf socketpair strerror \ |
672 | sysconf tcgetpgrp truncate utimes vhangup vsnprintf waitpid \ | 672 | strlcat strlcpy strmode strnvis sysconf tcgetpgrp truncate utimes \ |
673 | vhangup vsnprintf waitpid \ | ||
673 | ) | 674 | ) |
674 | 675 | ||
675 | AC_SEARCH_LIBS(nanosleep, rt posix4, AC_DEFINE(HAVE_NANOSLEEP)) | 676 | AC_SEARCH_LIBS(nanosleep, rt posix4, AC_DEFINE(HAVE_NANOSLEEP)) |
diff --git a/includes.h b/includes.h index b968be7f8..c30c31577 100644 --- a/includes.h +++ b/includes.h | |||
@@ -68,6 +68,7 @@ static /**/const char *const rcsid[] = { (char *)rcsid, "\100(#)" msg } | |||
68 | #ifdef HAVE_NEXT | 68 | #ifdef HAVE_NEXT |
69 | # include <libc.h> | 69 | # include <libc.h> |
70 | #endif | 70 | #endif |
71 | #define __USE_GNU /* before unistd.h, activate extra prototypes for glibc */ | ||
71 | #include <unistd.h> /* For STDIN_FILENO, etc */ | 72 | #include <unistd.h> /* For STDIN_FILENO, etc */ |
72 | #include <termios.h> /* Struct winsize */ | 73 | #include <termios.h> /* Struct winsize */ |
73 | 74 | ||
@@ -143,16 +143,63 @@ restore_uid(void) | |||
143 | void | 143 | void |
144 | permanently_set_uid(struct passwd *pw) | 144 | permanently_set_uid(struct passwd *pw) |
145 | { | 145 | { |
146 | uid_t old_uid = getuid(); | ||
147 | gid_t old_gid = getgid(); | ||
148 | |||
146 | if (temporarily_use_uid_effective) | 149 | if (temporarily_use_uid_effective) |
147 | fatal("permanently_set_uid: temporarily_use_uid effective"); | 150 | fatal("permanently_set_uid: temporarily_use_uid effective"); |
148 | debug("permanently_set_uid: %u/%u", (u_int)pw->pw_uid, | 151 | debug("permanently_set_uid: %u/%u", (u_int)pw->pw_uid, |
149 | (u_int)pw->pw_gid); | 152 | (u_int)pw->pw_gid); |
153 | |||
154 | #if defined(HAVE_SETRESGID) | ||
155 | if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) < 0) | ||
156 | fatal("setresgid %u: %.100s", (u_int)pw->pw_gid, strerror(errno)); | ||
157 | #elif defined(HAVE_SETREGID) | ||
158 | if (setregid(pw->pw_gid, pw->pw_gid) < 0) | ||
159 | fatal("setregid %u: %.100s", (u_int)pw->pw_gid, strerror(errno)); | ||
160 | #else | ||
150 | if (setegid(pw->pw_gid) < 0) | 161 | if (setegid(pw->pw_gid) < 0) |
151 | fatal("setegid %u: %.100s", (u_int)pw->pw_gid, strerror(errno)); | 162 | fatal("setegid %u: %.100s", (u_int)pw->pw_gid, strerror(errno)); |
152 | if (setgid(pw->pw_gid) < 0) | 163 | if (setgid(pw->pw_gid) < 0) |
153 | fatal("setgid %u: %.100s", (u_int)pw->pw_gid, strerror(errno)); | 164 | fatal("setgid %u: %.100s", (u_int)pw->pw_gid, strerror(errno)); |
165 | #endif | ||
166 | |||
167 | #if defined(HAVE_SETRESUID) | ||
168 | if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) < 0) | ||
169 | fatal("setresuid %u: %.100s", (u_int)pw->pw_uid, strerror(errno)); | ||
170 | #elif defined(HAVE_SETRESUID) | ||
171 | if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) < 0) | ||
172 | fatal("setresuid %u: %.100s", (u_int)pw->pw_uid, strerror(errno)); | ||
173 | #else | ||
174 | # ifndef SETEUID_BREAKS_SETUID | ||
154 | if (seteuid(pw->pw_uid) < 0) | 175 | if (seteuid(pw->pw_uid) < 0) |
155 | fatal("seteuid %u: %.100s", (u_int)pw->pw_uid, strerror(errno)); | 176 | fatal("seteuid %u: %.100s", (u_int)pw->pw_uid, strerror(errno)); |
177 | # endif | ||
156 | if (setuid(pw->pw_uid) < 0) | 178 | if (setuid(pw->pw_uid) < 0) |
157 | fatal("setuid %u: %.100s", (u_int)pw->pw_uid, strerror(errno)); | 179 | fatal("setuid %u: %.100s", (u_int)pw->pw_uid, strerror(errno)); |
180 | #endif | ||
181 | |||
182 | /* Try restoration of GID if changed (test clearing of saved gid) */ | ||
183 | if (old_gid != pw->pw_gid && | ||
184 | (setgid(old_gid) != -1 || setegid(old_gid) != -1)) | ||
185 | fatal("%s: was able to restore old [e]gid"); | ||
186 | |||
187 | /* Verify GID drop was successful */ | ||
188 | if (getgid() != pw->pw_gid || getegid() != pw->pw_gid) { | ||
189 | fatal("%s: egid incorrect gid:%u egid:%u (should be %u)", | ||
190 | __func__, (u_int)getgid(), (u_int)getegid(), | ||
191 | (u_int)pw->pw_gid); | ||
192 | } | ||
193 | |||
194 | /* Try restoration of UID if changed (test clearing of saved uid) */ | ||
195 | if (old_uid != pw->pw_uid && | ||
196 | (setuid(old_uid) != -1 || seteuid(old_uid) != -1)) | ||
197 | fatal("%s: was able to restore old [e]uid"); | ||
198 | |||
199 | /* Verify UID drop was successful */ | ||
200 | if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid) { | ||
201 | fatal("%s: euid incorrect uid:%u euid:%u (should be %u)", | ||
202 | __func__, (u_int)getuid(), (u_int)geteuid(), | ||
203 | (u_int)pw->pw_uid); | ||
204 | } | ||
158 | } | 205 | } |